Модуль os: работа с файловой системой из Python
Модуль os в Python дает доступ к функциям операционной системы: текущему каталогу, списку файлов, созданию и удалению папок, путям и переменным окружения. Он входит в стандартную библиотеку, поэтому устанавливать ничего не нужно, достаточно написать import os. Ниже разобраны функции, которые чаще всего встречаются в реальных скриптах, с рабочими примерами и разбором ошибок.

Содержание статьи
Что входит в модуль os
Модуль собирает в одном месте вызовы, которые в разных системах устроены по-разному. Один и тот же код с os.listdir() или os.path.join() работает в Windows, Linux и macOS. Часть функций доступна только в Unix, например os.fork() и os.getuid(), и в Windows их вызов закончится AttributeError.
Функции модуля удобно разделить на группы:
- текущий каталог и навигация:
getcwd(),chdir(); - содержимое папок:
listdir(),scandir(),walk(); - создание и удаление:
mkdir(),makedirs(),remove(),rmdir(),rename(); - работа с путями: подмодуль
os.path; - окружение и система:
environ,getenv(),name,cpu_count().
Полный перечень функций с пометками о поддерживаемых платформах есть в официальной документации os.
Текущий каталог и переход между папками
Относительные пути вроде "data.txt" Python ищет от текущего рабочего каталога. Это не обязательно папка, где лежит скрипт: если запустить программу из другой директории, файл не найдется. Узнать текущий каталог помогает os.getcwd(), сменить его можно через os.chdir().
import os
print(os.getcwd()) # C:\Users\user\project
script_dir = os.path.dirname(os.path.abspath(__file__))
os.chdir(script_dir) # теперь пути считаются от папки скрипта
print(os.getcwd())Менять рабочий каталог в больших программах лучше осторожно: это глобальная настройка процесса, и она влияет на все модули. Надежнее строить полные пути от script_dir и передавать их в функции.
Список файлов в каталоге
Функция os.listdir(path) возвращает список имен файлов и папок без полного пути и в произвольном порядке. Если аргумент не передан, берется текущий каталог. Для сортировки результат оборачивают в sorted().
import os
for name in sorted(os.listdir(".")):
full = os.path.join(".", name)
kind = "папка" if os.path.isdir(full) else "файл"
print(f"{kind}: {name}")os.scandir для больших папок
os.scandir() возвращает итератор объектов DirEntry. У каждого есть name, path, методы is_file(), is_dir() и stat(). Тип файла часто известен системе сразу, поэтому лишних обращений к диску меньше, и на тысячах файлов scandir() работает заметно быстрее связки listdir() и os.path.isfile().
import os
with os.scandir(".") as entries:
for entry in entries:
if entry.is_file() and entry.name.endswith(".py"):
print(entry.name, entry.stat().st_size, "байт")Обход дерева каталогов через os.walk
os.walk(top) рекурсивно проходит все вложенные папки и на каждом шаге отдает кортеж из трех значений: путь к текущей папке, список подпапок и список файлов. Список подпапок можно менять на ходу, чтобы пропустить ненужные каталоги.
import os
total = 0
for root, dirs, files in os.walk("project"):
dirs[:] = [d for d in dirs if d not in (".git", "__pycache__")]
for name in files:
total += os.path.getsize(os.path.join(root, name))
print(f"Размер: {total / 1024:.1f} КБ")Если нужен поиск по шаблону вроде *.csv, короче получится с модулем glob.
Создание, переименование и удаление
Функции этой группы меняют файловую систему, поэтому чаще других вызывают исключения: FileExistsError, FileNotFoundError, PermissionError. В рабочем коде их стоит перехватывать или заранее проверять условия.
Папки: mkdir и makedirs
os.mkdir() создает одну папку и падает, если родительского каталога нет. os.makedirs() создает всю цепочку, а с параметром exist_ok=True не выдает ошибку, когда папка уже существует.
import os
os.makedirs("reports/2026/october", exist_ok=True)
try:
os.mkdir("reports")
except FileExistsError:
print("Папка reports уже есть")Файлы: remove, rename и replace
os.remove() удаляет файл, а для пустой папки нужен os.rmdir(). Переименование и перемещение в пределах одного диска выполняет os.rename(src, dst). В Windows он выдает ошибку, если dst уже существует, а os.replace() в этом случае молча перезапишет файл на любой системе.
import os
with open("draft.txt", "w", encoding="utf-8") as f:
f.write("черновик")
os.replace("draft.txt", "final.txt")
if os.path.exists("final.txt"):
os.remove("final.txt")Удалить непустую папку целиком или скопировать дерево каталогов модуль os не умеет. Для этого есть модуль shutil с функциями rmtree() и copytree().
Подмодуль os.path для работы с путями
Склеивать пути через + и слеш опасно: в Windows разделитель обратный, и легко получить двойной или пропущенный слеш. os.path берет это на себя и подставляет разделитель текущей системы.
| Функция | Что делает | Пример результата |
|---|---|---|
join(a, b) | соединяет части пути | data/2026/log.txt |
exists(p) | есть ли файл или папка | True |
isfile(p), isdir(p) | проверяет тип объекта | True / False |
basename(p) | имя файла из пути | log.txt |
dirname(p) | путь к папке | data/2026 |
splitext(p) | отделяет расширение | ('data/2026/log', '.txt') |
abspath(p) | полный путь от корня | /home/user/data/2026/log.txt |
getsize(p) | размер файла в байтах | 2048 |
import os
path = os.path.join("data", "2026", "log.txt")
name, ext = os.path.splitext(os.path.basename(path))
print(name, ext) # log .txtВ новом коде вместо os.path часто используют объектный подход модуля pathlib, его сравнение со старыми функциями есть в статье pathlib вместо os.path.
Переменные окружения и сведения о системе
os.environ ведет себя как словарь со всеми переменными окружения процесса. Для чтения безопаснее os.getenv("NAME", default): при отсутствии переменной он вернет значение по умолчанию вместо KeyError. Так обычно передают в программу токены, пароли к базе и режим отладки, чтобы не хранить их в коде.
import os
debug = os.getenv("APP_DEBUG", "0") == "1"
os.environ["APP_MODE"] = "test" # видно только этому процессу и его потомкам
print(os.name) # 'nt' в Windows, 'posix' в Linux и macOS
print(os.sep) # разделитель пути: '\\' или '/'
print(os.cpu_count()) # число логических ядер
print(os.getpid()) # номер текущего процессаИзменения в os.environ не сохраняются в системе после завершения скрипта: они действуют только внутри процесса и передаются запущенным из него программам.
Запуск системных команд
os.system("команда") выполняет строку в командной оболочке и возвращает код завершения, но вывод команды получить нельзя, он сразу идет в консоль. os.popen() позволяет прочитать вывод, однако оба способа передают строку в оболочку целиком, и подстановка пользовательского ввода в такую строку открывает дорогу для инъекций.
Для новых программ документация советует модуль subprocess. Аргументы передаются списком, без оболочки, а результат содержит код возврата и вывод.
import subprocess
result = subprocess.run(["python", "--version"], capture_output=True, text=True)
print(result.returncode) # 0
print(result.stdout.strip()) # Python 3.12.4Частые вопросы
Ниже ответы на вопросы, с которыми чаще всего сталкиваются при работе с модулем os.
Нужно ли устанавливать модуль os через pip?
Нет. Модуль входит в стандартную библиотеку и доступен в любой установке Python, достаточно импортировать его командой import os.
Как проверить, существует ли файл?
Используйте os.path.exists(path) для любого объекта или os.path.isfile(path), если нужно убедиться, что это именно файл, а не папка с таким же именем.
Почему os.remove не удаляет папку?
os.remove() работает только с файлами. Пустую папку удаляет os.rmdir(), а папку с содержимым shutil.rmtree().
Как получить путь к папке, где лежит скрипт?
Выражение os.path.dirname(os.path.abspath(__file__)) возвращает каталог текущего файла независимо от того, откуда запущена программа.
Что выбрать: os.path или pathlib?
Оба варианта рабочие. pathlib удобнее читается и объединяет пути оператором /, а os.path встречается в старом коде и в библиотеках, поэтому знать стоит оба.