Python & AI Tutorials Logo
Программирование Python

29. Взаимодействие с операционной системой: sys и os

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

Понимание этих модулей превращает ваши скрипты Python из изолированного кода в программы, которые могут интегрироваться с более широкой системой, реагировать на ввод пользователя при запуске и программно управлять файлами и папками.

29.1) Аргументы командной строки и использование sys.argv

Когда вы запускаете скрипт Python из терминала или командной строки, вы можете передать ему дополнительную информацию — она называется аргументами командной строки (command-line arguments). Например:

bash
python greet.py Alice 25

Здесь greet.py — имя скрипта, а Alice и 25 — аргументы, переданные программе. Модуль sys предоставляет доступ к этим аргументам через sys.argv, список(list), содержащий имя скрипта и все аргументы в виде строк.

29.1.1) Что такое sys.argv?

sys.argv — это список(list), в котором:

  • sys.argv[0] — всегда имя запускаемого скрипта
  • sys.argv[1], sys.argv[2] и т. д. — аргументы, переданные после имени скрипта
  • Все элементы — строки, даже если они выглядят как числа

Создадим простой скрипт, чтобы посмотреть, как это работает:

python
# show_args.py
import sys
 
print("Script name:", sys.argv[0])
print("Number of arguments:", len(sys.argv))
print("All arguments:", sys.argv)

Если вы запустите этот скрипт так:

bash
python show_args.py hello world 123

Output:

Script name: show_args.py
Number of arguments: 4
All arguments: ['show_args.py', 'hello', 'world', '123']

Обратите внимание, что sys.argv содержит 4 элемента: имя скрипта плюс три аргумента. Число 123 хранится как строка '123', а не как целое число.

29.1.2) Использование аргументов командной строки в программах

Аргументы командной строки позволяют пользователям настраивать поведение программы без изменения кода. Вот программа приветствия, которая использует первый аргумент как имя:

python
# greet.py
import sys
 
if len(sys.argv) < 2:
    print("Usage: python greet.py <name>")
    sys.exit(1)  # Завершить работу с кодом ошибки
 
name = sys.argv[1]
print(f"Hello, {name}!")

Запуск:

bash
python greet.py Alice

Output:

Hello, Alice!

Если вы забудете указать имя:

bash
python greet.py

Output:

Usage: python greet.py <name>

Программа проверяет, было ли передано достаточно аргументов. Если нет, она выводит сообщение об использовании и завершает работу с sys.exit(1). Число 1 — это код завершения (exit code) — по соглашению 0 означает успех, а ненулевые значения указывают на ошибки. Это помогает другим программам или скриптам определить, успешно ли выполнилась ваша программа.

29.1.3) Преобразование аргументов в другие типы

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

python
# area.py
import sys
 
if len(sys.argv) < 3:
    print("Usage: python area.py <width> <height>")
    sys.exit(1)
 
try:
    width = float(sys.argv[1])
    height = float(sys.argv[2])
except ValueError:
    print("Error: Width and height must be numbers")
    sys.exit(1)
 
area = width * height
print(f"Area: {area}")

Запуск:

bash
python area.py 5.5 3.2

Output:

Area: 17.6

Если пользователь введёт некорректные данные:

bash
python area.py five three

Output:

Error: Width and height must be numbers

Блок try-except (из Главы 25) корректно обрабатывает ошибки преобразования, выдавая полезную обратную связь вместо аварийного завершения с traceback.

Пользователь запускает: python script.py arg1 arg2

Python создаёт список sys.argv

sys.argv[0] = 'script.py'

sys.argv[1] = 'arg1'

sys.argv[2] = 'arg2'

Скрипт обращается к sys.argv

Обработка аргументов как строк

Преобразование типов при необходимости

Использование значений в логике программы

29.2) Получение информации об интерпретаторе и окружении выполнения с sys

Модуль sys предоставляет информацию о самом интерпретаторе Python и среде выполнения. Это полезно для отладки(debugging), логирования или написания кода, который адаптируется к разным версиям Python или платформам.

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

sys.version и sys.version_info сообщают, какая версия Python выполняет ваш код:

python
import sys
 
print("Python version string:", sys.version)
print("Version info:", sys.version_info)
print(f"Major version: {sys.version_info.major}")
print(f"Minor version: {sys.version_info.minor}")

Output (example):

Python version string: 3.11.4 (main, Jul  5 2023, 13:45:01) [GCC 11.2.0]
Version info: sys.version_info(major=3, minor=11, micro=4, releaselevel='final', serial=0)
Major version: 3
Minor version: 11

sys.version — человекочитаемая строка, а sys.version_info — именованный кортеж, который можно сравнивать программно:

python
import sys
 
if sys.version_info < (3, 8):
    print("This program requires Python 3.8 or higher")
    sys.exit(1)
 
print("Python version is compatible")

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

29.2.2) Информация о платформе

sys.platform идентифицирует операционную систему:

python
import sys
 
print("Platform:", sys.platform)
 
if sys.platform == "win32":
    print("Running on Windows")
elif sys.platform == "darwin":
    print("Running on macOS")
elif sys.platform.startswith("linux"):
    print("Running on Linux")
else:
    print("Running on another platform")

Output (on Linux):

Platform: linux
Running on Linux

Это позволяет при необходимости писать платформо-зависимый код, например использовать разные пути к файлам или системные команды.

29.2.3) Путь поиска модулей

sys.path — это список(list) каталогов, в которых Python ищет модули при импорте:

python
import sys
 
print("Module search paths:")
for path in sys.path:
    print(f"  {path}")

Output (example):

Module search paths:
  /home/user/projects
  /usr/lib/python3.11
  /usr/lib/python3.11/lib-dynload
  /home/user/.local/lib/python3.11/site-packages

Первая запись обычно — это каталог, содержащий ваш скрипт. Python ищет по этим путям по порядку, когда вы используете import. Понимание sys.path помогает отлаживать ошибки импорта или добавлять пользовательские каталоги модулей.

29.2.4) Завершение программ с кодами выхода

Мы уже видели sys.exit(), используемый для остановки программ. Вы можете передать код завершения, чтобы указать на успех или неудачу:

python
import sys
 
def process_data(filename):
    try:
        with open(filename) as f:
            data = f.read()
        # Обработать данные...
        return True
    except FileNotFoundError:
        print(f"Error: File '{filename}' not found", file=sys.stderr)
        return False
 
if __name__ == "__main__":
    if len(sys.argv) < 2:
        print("Usage: python script.py <filename>", file=sys.stderr)
        sys.exit(1)
    
    success = process_data(sys.argv[1])
    sys.exit(0 if success else 1)

Коды завершения следуют соглашениям Unix:

  • 0 означает успех
  • ненулевые значения указывают на разные типы ошибок
  • другие программы могут проверять эти коды, чтобы определить, выполнилась ли ваша программа успешно

29.3) Доступ к переменным окружения с os

Переменные окружения (environment variables) — это пары ключ-значение, задаваемые операционной системой или пользователем, которые могут читать программы. Они используются для конфигурации, хранения путей, API-ключей и других настроек, которые не следует жёстко прописывать в коде.

29.3.1) Чтение переменных окружения

Модуль os предоставляет os.environ, объект, похожий на словарь(dict), содержащий все переменные окружения:

python
import os
 
# Получить конкретную переменную окружения
home = os.environ.get('HOME')  # На Unix/Linux/macOS
print(f"Home directory: {home}")
 
# Возвращает None, если переменная не существует
api_key = os.environ.get('MY_API_KEY')
print(f"API key: {api_key}")

Output (on Linux):

Home directory: /home/alice
API key: None

Можно указать значение по умолчанию:

python
import os
 
# Получить переменную окружения со значением по умолчанию
log_level = os.environ.get('LOG_LEVEL', 'INFO')
print(f"Log level: {log_level}")

Output (if LOG_LEVEL not set):

Log level: INFO

29.3.2) Распространённые переменные окружения

Разные операционные системы предоставляют стандартные переменные окружения:

python
import os
 
# Кроссплатформенные переменные
print("Path:", os.environ.get('PATH'))
 
# Unix/Linux/macOS
print("User:", os.environ.get('USER'))
print("Home:", os.environ.get('HOME'))
print("Shell:", os.environ.get('SHELL'))
 
# Windows
print("User", os.environ.get('USERNAME'))
print("User Profile:", os.environ.get('USERPROFILE'))
print("Temp:", os.environ.get('TEMP'))

PATH особенно важна — она содержит список каталогов, где система ищет исполняемые программы. Когда вы вводите команду вроде python, система выполняет поиск в этих каталогах.

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

Вы можете изменять переменные окружения для своей программы и любых подпроцессов(subprocess), которые она создаёт:

python
import os
 
# Установить переменную окружения
os.environ['MY_CONFIG'] = 'production'
 
# Прочитать её обратно
print(os.environ.get('MY_CONFIG'))  # Output: production
 
# Удалить переменную окружения
del os.environ['MY_CONFIG']

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

29.4) Работа с путями к файлам и каталогами (os.path, os.getcwd)

Корректное управление путями к файлам критически важно для программ, работающих с файлами. Модули os и os.path предоставляют инструменты для построения, изменения и проверки путей платформо-независимым способом.

29.4.1) Получение текущего рабочего каталога

Текущий рабочий каталог (current working directory, CWD) — это папка, которую программа считает отправной точкой для относительных путей:

python
import os
 
cwd = os.getcwd()
print(f"Current working directory: {cwd}")

Output (example):

Current working directory: /home/alice/projects/myapp

Когда вы открываете файл по относительному пути вроде 'data.txt', Python ищет его в текущем рабочем каталоге. Понимание CWD помогает отлаживать ошибки «файл не найден».

29.4.2) Изменение текущего каталога

Вы можете изменить рабочий каталог с помощью os.chdir():

python
import os
 
original = os.getcwd()
print("Original directory:", original)
 
# Перейти в другой каталог
os.chdir('/tmp')
print("New directory:", os.getcwd())
 
# Вернуться обратно
os.chdir(original)
print("Back to:", os.getcwd())

Output:

Original directory: /home/alice/projects
New directory: /tmp
Back to: /home/alice/projects

Примечание: В Главе 28 вы узнали про contextlib.chdir(), который автоматически восстанавливает исходный каталог. Для простого изменения каталога предпочтительнее использовать контекстный менеджер(context manager):

python
from contextlib import chdir
 
with chdir('/tmp'):
    print("Temporarily in:", os.getcwd())
# Автоматически восстановлено

Это гарантирует, что каталог всегда будет восстановлен, даже если возникнет ошибка.

29.4.3) Построение путей с os.path.join()

Разные операционные системы используют разные разделители пути:

  • Unix/Linux/macOS: / (прямой слеш)
  • Windows: \ (обратный слеш)

os.path.join() корректно строит пути для текущей платформы:

python
import os
 
# Построить путь к файлу в подкаталоге
data_dir = 'data'
filename = 'users.txt'
filepath = os.path.join(data_dir, filename)
 
print(f"File path: {filepath}")

Output (on Unix/Linux/macOS):

File path: data/users.txt

Output (on Windows):

File path: data\users.txt

Можно объединять несколько компонентов:

python
import os
 
base = '/home/alice'
project = 'myapp'
subdir = 'data'
file = 'config.json'
 
full_path = os.path.join(base, project, subdir, file)
print(full_path)  # Output: /home/alice/myapp/data/config.json

Использование os.path.join() делает ваш код переносимым между операционными системами.

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

Перед работой с файлами или каталогами проверьте, существуют ли они:

python
import os
 
path = 'data.txt'
 
if os.path.exists(path):
    print(f"'{path}' exists")
else:
    print(f"'{path}' does not exist")

Также можно проверить конкретно файлы или каталоги:

python
import os
 
path = 'mydir'
 
if os.path.isfile(path):
    print(f"'{path}' is a file")
elif os.path.isdir(path):
    print(f"'{path}' is a directory")
elif os.path.exists(path):
    print(f"'{path}' exists but is neither a file nor directory")
else:
    print(f"'{path}' does not exist")

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

29.4.5) Получение абсолютных путей

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

python
import os
 
relative_path = 'data/users.txt'
absolute_path = os.path.abspath(relative_path)
 
print(f"Relative: {relative_path}")
print(f"Absolute: {absolute_path}")

Output (example):

Relative: data/users.txt
Absolute: /home/alice/projects/myapp/data/users.txt

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

29.4.6) Разделение пути на компоненты

os.path.split() разделяет путь на каталог и имя файла:

python
import os
 
path = '/home/alice/projects/data.txt'
directory, filename = os.path.split(path)
 
print(f"Directory: {directory}")
print(f"Filename: {filename}")

Output:

Directory: /home/alice/projects
Filename: data.txt

os.path.basename() получает только имя файла, а os.path.dirname() — только каталог:

python
import os
 
path = '/home/alice/projects/data.txt'
 
print(f"Basename: {os.path.basename(path)}")  # Output: data.txt
print(f"Dirname: {os.path.dirname(path)}")    # Output: /home/alice/projects

29.4.7) Разделение расширений файлов

os.path.splitext() отделяет имя файла от расширения:

python
import os
 
filename = 'report.pdf'
name, extension = os.path.splitext(filename)
 
print(f"Name: {name}")        # Output: report
print(f"Extension: {extension}")  # Output: .pdf

Это полезно для обработки файлов в зависимости от их типа:

python
import os
 
files = ['data.csv', 'image.png', 'document.txt', 'script.py']
 
for file in files:
    name, ext = os.path.splitext(file)
    if ext == '.csv':
        print(f"Process CSV file: {file}")
    elif ext == '.png':
        print(f"Process image file: {file}")

Output:

Process CSV file: data.csv
Process image file: image.png

29.5) Просмотр, создание и удаление файлов и каталогов

Модуль os предоставляет функции для работы с файловой системой: просмотр содержимого каталога, создание новых каталогов и удаление файлов и папок.

29.5.1) Просмотр содержимого каталога

os.listdir() возвращает список(list) всех элементов в каталоге:

python
import os
 
# Вывести содержимое текущего каталога
contents = os.listdir('.')
print("Current directory contents:")
for item in contents:
    print(f"  {item}")

Output (example):

Current directory contents:
  script.py
  data.txt
  mydir
  README.md

Список включает как файлы, так и каталоги. Чтобы различать их:

python
import os
 
contents = os.listdir('.')
print("Files:")
for item in contents:
    if os.path.isfile(item):
        print(f"  {item}")
 
print("\nDirectories:")
for item in contents:
    if os.path.isdir(item):
        print(f"  {item}")

Output:

Files:
  script.py
  data.txt
  README.md
 
Directories:
  mydir

29.5.2) Создание каталогов

os.mkdir() создаёт один каталог:

python
import os
 
new_dir = 'output'
 
if not os.path.exists(new_dir):
    os.mkdir(new_dir)
    print(f"Created directory: {new_dir}")
else:
    print(f"Directory already exists: {new_dir}")

Output:

Created directory: output

Важно: os.mkdir() завершится ошибкой, если родительского каталога не существует. Например, попытка создать 'data/output', когда 'data' не существует, вызовет ошибку.

os.makedirs() создаёт все необходимые родительские каталоги:

python
import os
 
nested_dir = 'data/processed/2024'
 
if not os.path.exists(nested_dir):
    os.makedirs(nested_dir)
    print(f"Created directory structure: {nested_dir}")

Output:

Created directory structure: data/processed/2024

Это создаст data, затем data/processed, затем data/processed/2024, если они не существуют.

29.5.3) Удаление файлов

os.remove() удаляет файл:

python
import os
 
filename = 'temp.txt'
 
# Создать временный файл
with open(filename, 'w') as f:
    f.write('Temporary data')
 
print(f"File exists: {os.path.exists(filename)}")  # Output: True
 
# Удалить файл
os.remove(filename)
print(f"File exists: {os.path.exists(filename)}")  # Output: False

Предупреждение: os.remove() удаляет файлы навсегда — они не попадают в корзину.

29.5.4) Удаление каталогов

os.rmdir() удаляет пустой каталог:

python
import os
 
directory = 'empty_dir'
 
# Создать и затем удалить пустой каталог
os.mkdir(directory)
print(f"Created: {directory}")
 
os.rmdir(directory)
print(f"Removed: {directory}")

os.rmdir() завершится ошибкой, если в каталоге есть файлы. Чтобы удалить каталог и всё его содержимое, нужно сначала удалить файлы:

python
import os
 
def remove_directory_contents(directory):
    """Удалить все файлы в каталоге, затем удалить каталог.
    
    Примечание: Не сработает, если каталог содержит подкаталоги.
    """
    if not os.path.exists(directory):
        print(f"Directory does not exist: {directory}")
        return
    
    # Удалить все файлы в каталоге
    for item in os.listdir(directory):
        item_path = os.path.join(directory, item)
        if os.path.isfile(item_path):
            os.remove(item_path)
            print(f"Removed file: {item_path}")
    
    # Удалить теперь уже пустой каталог
    os.rmdir(directory)
    print(f"Removed directory: {directory}")
 
# Пример использования
test_dir = 'test_data'
os.makedirs(test_dir, exist_ok=True)
 
# Создать несколько тестовых файлов
with open(os.path.join(test_dir, 'file1.txt'), 'w') as f:
    f.write('test')
with open(os.path.join(test_dir, 'file2.txt'), 'w') as f:
    f.write('test')
 
# Удалить всё
remove_directory_contents(test_dir)

Output:

Removed file: test_data/file1.txt
Removed file: test_data/file2.txt
Removed directory: test_data

Примечание: Для более сложного удаления каталогов (включая подкаталоги) модуль shutil предоставляет shutil.rmtree(), но это выходит за рамки нашей текущей темы.

29.5.5) Переименование файлов и каталогов

os.rename() переименовывает или перемещает файлы и каталоги:

python
import os
 
# Переименовать файл
old_name = 'draft.txt'
new_name = 'final.txt'
 
# Создать тестовый файл
with open(old_name, 'w') as f:
    f.write('content')
 
os.rename(old_name, new_name)
print(f"Renamed '{old_name}' to '{new_name}'")

Также можно перемещать файлы в другие каталоги:

python
import os
 
# Создать каталоги и файл
os.makedirs('source', exist_ok=True)
os.makedirs('destination', exist_ok=True)
 
with open('source/file.txt', 'w') as f:
    f.write('content')
 
# Переместить файл в другой каталог
os.rename('source/file.txt', 'destination/file.txt')
print("Moved file to destination directory")

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


© 2025. Primesoft Co., Ltd.
support@primesoft.ai