W3docs

Модули os и sys в Python

Освойте модули os и sys в Python: навигация по файловой системе, управление переменными окружения, проверка состояния интерпретатора и обработка аргументов командной строки.

Модули os и sys — два из наиболее важных инструментов стандартной библиотеки Python. os связывает Python с операционной системой — позволяет перемещаться по директориям, просматривать и задавать переменные окружения, а также управлять файлами и путями. sys связывает Python с самим интерпретатором — предоставляет список аргументов, путь поиска модулей и хуки для управления завершением работы интерпретатора. Вместе они охватывают почти всё, что нужно скрипту для взаимодействия со средой выполнения.

Модуль os

Импортируйте os в начале скрипта:

import os

Установка не требуется — модуль поставляется с каждым дистрибутивом Python.

Работа с директориями

Получение и изменение текущей рабочей директории

os.getcwd() возвращает абсолютный путь к директории, в которой выполняется скрипт. os.chdir() изменяет её.

import os

# Print the current directory
print(os.getcwd())
# Example output: /Users/alice/projects

# Change to a different directory
os.chdir("/tmp")
print(os.getcwd())
# Output: /tmp

Список содержимого директории

os.listdir(path) возвращает список всех элементов (файлов и поддиректорий) в path. Рекурсивный обход поддиректорий не выполняется.

import os

entries = os.listdir(".")   # "." means current directory
for entry in sorted(entries):
    print(entry)

Для различия файлов и директорий используйте os.path.isfile() и os.path.isdir():

import os

for entry in os.listdir("."):
    if os.path.isdir(entry):
        print(f"[DIR]  {entry}")
    else:
        print(f"[FILE] {entry}")

Создание и удаление директорий

import os

# Create a single directory
os.mkdir("reports")

# Create nested directories in one call
os.makedirs("data/2024/january", exist_ok=True)
# exist_ok=True prevents an error if the directory already exists

# Remove an empty directory
os.rmdir("reports")

# Remove a full directory tree
import shutil
shutil.rmtree("data")

Параметр exist_ok=True в os.makedirs() очень полезен в скриптах, которые могут запускаться несколько раз — без него повторный запуск вызовет ошибку FileExistsError.

Обход дерева директорий

os.walk(top) генерирует тройки (dirpath, dirnames, filenames) для каждой директории в дереве, начиная с top. Это стандартный способ рекурсивного обхода структуры папок.

import os

for dirpath, dirnames, filenames in os.walk("project"):
    level = dirpath.count(os.sep)
    indent = "  " * level
    print(f"{indent}{os.path.basename(dirpath)}/")
    for filename in filenames:
        print(f"{indent}  {filename}")

Работа с путями к файлам

Подмодуль os.path содержит переносимые утилиты для работы с путями, которые корректно работают в Windows, macOS и Linux.

Объединение компонентов пути

os.path.join() объединяет части пути, используя правильный разделитель для текущей ОС.

import os

base = "/home/alice"
project = "myapp"
filename = "config.json"

full_path = os.path.join(base, project, filename)
print(full_path)
# Output: /home/alice/myapp/config.json

Никогда не строите пути через конкатенацию строк вроде base + "/" + filename — это ломается в Windows. Всегда используйте os.path.join().

Разбиение пути

import os

path = "/home/alice/myapp/config.json"

print(os.path.dirname(path))   # /home/alice/myapp
print(os.path.basename(path))  # config.json
print(os.path.split(path))     # ('/home/alice/myapp', 'config.json')
print(os.path.splitext(path))  # ('/home/alice/myapp/config', '.json')

os.path.splitext() удобно использовать, когда нужно убрать или изменить расширение файла.

Проверка существования пути

import os

print(os.path.exists("/tmp"))      # True (usually)
print(os.path.isfile("/tmp"))      # False — it is a directory
print(os.path.isdir("/tmp"))       # True
print(os.path.isabs("/tmp"))       # True — it is an absolute path

Получение абсолютного пути

os.path.abspath() преобразует относительный путь в абсолютный относительно текущей рабочей директории:

import os

print(os.path.abspath("config.json"))
# Example output: /home/alice/myapp/config.json

Это полезно, когда нужно сохранить или записать в лог путь, который должен оставаться корректным даже при последующем изменении рабочей директории.

Переменная __file__ и пути относительно скрипта

Распространённая ловушка: скрипт, открывающий "data.csv", работает при запуске из собственной директории, но ломается при запуске из другой. Решение — строить путь относительно самого файла скрипта:

import os

# Directory that contains *this* script
HERE = os.path.dirname(os.path.abspath(__file__))

data_file = os.path.join(HERE, "data.csv")
with open(data_file, encoding="utf-8") as f:
    content = f.read()

Этот приём делает скрипты переносимыми вне зависимости от того, из какой директории они запускаются.

Переменные окружения

Переменные окружения хранят конфигурацию за пределами исходного кода — URL баз данных, API-ключи, флаги функций и тому подобное. Отображение os.environ предоставляет доступ на чтение и запись к переменным окружения текущего процесса.

Чтение переменной окружения

import os

# Returns the value or None if not set
home = os.environ.get("HOME")
print(home)
# Example output: /home/alice

# Raise KeyError if not set (useful to fail fast on missing config)
path = os.environ["PATH"]

Предпочитайте os.environ.get(key) вместо os.environ[key], если только переменная не является строго обязательной и программа не должна завершиться без неё.

Чтение со значением по умолчанию

import os

debug = os.environ.get("DEBUG", "false")
port = int(os.environ.get("PORT", "8080"))

print(f"debug={debug}, port={port}")
# Output: debug=false, port=8080

Установка и удаление переменных окружения

import os

# Set a variable — affects only the current process and its children
os.environ["MY_APP_ENV"] = "production"

# Remove a variable
os.environ.pop("MY_APP_ENV", None)   # None prevents KeyError if not present

Установка значений os.environ не сохраняется после завершения процесса. Чтобы задать постоянные переменные окружения, измените профиль оболочки (~/.bashrc, ~/.zshrc) или используйте файл .env, загружаемый библиотекой наподобие python-dotenv.

Список всех переменных окружения

import os

for key, value in sorted(os.environ.items()):
    print(f"{key}={value}")

Запуск команд оболочки с помощью os.system() и subprocess

os.system(command) выполняет команду оболочки и возвращает её код завершения, но не позволяет перехватить вывод. Для чего-либо сложнее одноразового вызова используйте модуль subprocess.

import os
import subprocess

# Quick way — exit code only
exit_code = os.system("echo hello")
print("exit code:", exit_code)   # 0 means success

# Better way — capture output
result = subprocess.run(
    ["echo", "hello"],
    capture_output=True,
    text=True,
)
print(result.stdout.strip())   # hello

subprocess.run() мощнее и безопаснее os.system(), поскольку не задействует интерпретатор оболочки и позволяет перехватить stdout, stderr и код возврата как объекты Python.

Полезные утилиты os

ФункцияОписание
os.getcwd()Текущая рабочая директория
os.chdir(path)Изменить рабочую директорию
os.listdir(path)Список элементов директории
os.mkdir(path)Создать директорию
os.makedirs(path, exist_ok=True)Создать вложенные директории
os.rmdir(path)Удалить пустую директорию
os.remove(path)Удалить файл
os.rename(src, dst)Переименовать / переместить файл
os.walk(top)Рекурсивный обход дерева директорий
os.environОтображение переменных окружения
os.getpid()Идентификатор текущего процесса
os.cpu_count()Количество логических ядер CPU

Модуль sys

sys предоставляет информацию об интерпретаторе Python и хуки для управления его поведением.

import sys

Аргументы командной строки через sys.argv

sys.argv — это список строк. sys.argv[0] содержит имя скрипта; последующие элементы — аргументы, переданные в командной строке.

Предположим, вы сохранили скрипт как greet.py и запустили python greet.py Alice 42:

import sys

script_name = sys.argv[0]   # 'greet.py'
name = sys.argv[1]          # 'Alice'
age = sys.argv[2]           # '42' — always a string

print(f"Hello, {name}! You are {age} years old.")
# Output: Hello, Alice! You are 42 years old.

Всегда проверяйте sys.argv перед обращением к индексам — IndexError завершит скрипт с ошибкой, если пользователь забудет передать аргумент:

import sys

if len(sys.argv) != 3:
    print(f"Usage: python {sys.argv[0]} <name> <age>")
    sys.exit(1)

name = sys.argv[1]
age = sys.argv[2]
print(f"Hello, {name}! You are {age} years old.")

Для сложного разбора аргументов предпочтительно использовать модуль argparse из стандартной библиотеки — он автоматически генерирует вывод --help.

Завершение интерпретатора с помощью sys.exit()

sys.exit(code) вызывает SystemExit и завершает работу интерпретатора. По соглашению, код завершения 0 означает успех; любое ненулевое значение сигнализирует об ошибке.

import sys

answer = input("Continue? (y/n): ")
if answer.lower() != "y":
    print("Goodbye!")
    sys.exit(0)

print("Continuing...")

Вы можете перехватить SystemExit в блоке try/except, если нужно выполнить очистку перед завершением программы, но обычно оператор with (для файловых дескрипторов, сетевых соединений и т. д.) обрабатывает очистку автоматически.

Информация о версии Python

import sys

print(sys.version)
# Example: 3.10.15 (main, ...) [GCC 11.4.0]

print(sys.version_info)
# sys.version_info(major=3, minor=10, micro=15, ...)

# Guard against running on an unsupported Python version
if sys.version_info < (3, 8):
    sys.exit("This script requires Python 3.8 or later.")

sys.version_info — именованный кортеж, поэтому его можно напрямую сравнивать с кортежем целых чисел.

Путь поиска модулей (sys.path)

Когда вы пишете import mymodule, Python последовательно просматривает каждую директорию в sys.path, пока не найдёт подходящий файл. Список начинается с директории скрипта (или пустой строки для интерактивных сессий), затем следуют записи PYTHONPATH, стандартная библиотека и site-packages.

import sys

for p in sys.path:
    print(p)

Во время выполнения можно добавить записи в sys.path, чтобы импортировать модули из нестандартных мест:

import sys
import os

# Add a sibling directory to the search path
sys.path.insert(0, os.path.join(os.path.dirname(__file__), "libs"))

import mymodule   # now found in ./libs/mymodule.py

Изменение sys.path — быстрое решение для локальной разработки, но для распространяемых пакетов используйте pip и правильный pyproject.toml.

Стандартные потоки

sys.stdin, sys.stdout и sys.stderr — объекты, подобные файлам, подключённые к трём стандартным потокам. Их можно перенаправлять для перехвата или подавления вывода.

import sys

# Write to stdout (same as print, but more explicit)
sys.stdout.write("Hello, stdout\n")

# Write to stderr (errors and diagnostics)
sys.stderr.write("Warning: something looks off\n")

Распространённый приём в скриптах — перенаправить sys.stdout в файл для перехвата всего вывода print():

import sys

with open("output.log", "w", encoding="utf-8") as log:
    original_stdout = sys.stdout
    sys.stdout = log
    print("This goes to the log file.")
    sys.stdout = original_stdout

print("This goes back to the terminal.")

Полезные атрибуты sys

Атрибут / ФункцияЧто возвращает
sys.argvСписок аргументов командной строки
sys.versionСтрока с версией Python
sys.version_infoИменованный кортеж (major, minor, micro, ...)
sys.platformИдентификатор платформы ("linux", "darwin", "win32")
sys.pathПуть поиска модулей (список строк)
sys.modulesСловарь всех импортированных модулей
sys.stdinСтандартный поток ввода
sys.stdoutСтандартный поток вывода
sys.stderrСтандартный поток ошибок
sys.exit(code)Завершить интерпретатор с указанным кодом
sys.getrecursionlimit()Максимальная глубина рекурсии (по умолчанию 1000)
sys.maxsizeМаксимальное значение int на данной платформе

Совместное использование os и sys на практике

Реальные скрипты часто используют оба модуля вместе. Вот небольшой, но реалистичный пример: скрипт, сканирующий директорию на наличие файлов .log и выводящий сводку.

import os
import sys

def summarize_logs(directory):
    if not os.path.isdir(directory):
        sys.stderr.write(f"Error: '{directory}' is not a directory.\n")
        sys.exit(1)

    log_files = [
        f for f in os.listdir(directory)
        if f.endswith(".log") and os.path.isfile(os.path.join(directory, f))
    ]

    if not log_files:
        print("No .log files found.")
        return

    print(f"Found {len(log_files)} log file(s) in '{directory}':")
    for name in sorted(log_files):
        full_path = os.path.join(directory, name)
        size = os.path.getsize(full_path)
        print(f"  {name}  ({size} bytes)")

if len(sys.argv) != 2:
    print(f"Usage: python {sys.argv[0]} <directory>")
    sys.exit(1)

summarize_logs(sys.argv[1])

Запустите его как python summarize.py /var/log — скрипт выведет имя и размер в байтах каждого файла .log в этой директории.

os против pathlib — что выбрать?

В Python 3.4 был введён pathlib.Path — объектно-ориентированная альтернатива os.path. Оба подхода корректны; выбор в основном определяется стилевыми предпочтениями.

ЗадачаСтиль osСтиль pathlib
Объединить путиos.path.join(a, b)Path(a) / b
Получить имя файлаos.path.basename(p)Path(p).name
Получить расширениеos.path.splitext(p)[1]Path(p).suffix
Проверить существованиеos.path.exists(p)Path(p).exists()
Прочитать текстовый файлopen(p).read()Path(p).read_text()
Список директорииos.listdir(p)list(Path(p).iterdir())

pathlib даёт более читаемый код в скриптах с интенсивной работой с путями; os.path привычен и поддерживается везде, где работает Python 3. У модуля sys нет эквивалента в pathlib — он всегда подключается как import sys.

Практика

Практика
Which function returns the current working directory in Python?
Which function returns the current working directory in Python?
Практика
What does sys.argv[0] contain when you run a Python script from the command line?
What does sys.argv[0] contain when you run a Python script from the command line?

Связанные главы

Was this page helpful?