11 KiB
01. Python-окружения, зависимости и устройство проекта
Изолируем интерпретатор и зависимости так, чтобы проект одинаково запускался сегодня, на другой машине и в автоматической проверке.
Мотивация
Python-программа зависит не только от исходного кода. Результат могут изменить версия Python, версии библиотек, операционная система, переменные окружения и рабочий каталог. Фраза «у меня работает» обычно означает, что часть этих условий осталась неописанной.
Воспроизводимый проект делает условия явными. Это позволяет:
- не смешивать зависимости разных проектов;
- повторно собрать среду после поломки;
- отличить ошибку кода от несовместимости версий;
- передать проект без копирования локального окружения.
Интуитивная модель
Окружение — это отдельный набор инструментов для одного проекта. Интерпретатор Python
играет роль станка, пакеты — насадок, а файл зависимостей — спецификации комплекта.
Каталог .venv является расходным артефактом: его можно удалить и собрать снова.
Удобно разделять четыре слоя:
- исходники — то, что пишется и проверяется в Git;
- конфигурация — объявленные зависимости и параметры запуска;
- окружение — конкретно установленные пакеты;
- данные и результаты — входы и полученные артефакты.
Интерпретатор, пакет и импорт
Интерпретатор исполняет байткод Python. Команда python выбирается через PATH;
поэтому перед установкой пакетов важно проверить, какой именно Python запущен:
import sys
print(sys.executable)
print(sys.version)
Модуль — обычно один файл .py. Пакет — импортируемая директория модулей.
Дистрибутив — устанавливаемая единица, известная менеджеру пакетов. Имя
дистрибутива и имя импорта иногда различаются: устанавливается scikit-learn,
а импортируется sklearn.
Поиск при import name идёт по sys.path. В него входят каталог запуска,
стандартная библиотека, установленные пакеты и явно добавленные пути. Изменение
рабочего каталога может поэтому скрыть ошибку структуры проекта.
Создание виртуального окружения
Из корня проекта:
python -m venv .venv
Активация в PowerShell:
.\.venv\Scripts\Activate.ps1
python -m pip install --upgrade pip
В Linux и macOS путь активации — .venv/bin/activate. Активация лишь ставит
интерпретатор окружения раньше остальных в PATH. Можно не активировать среду,
а вызывать .venv\Scripts\python.exe напрямую.
Форма python -m pip безопаснее команды pip: модуль pip запускается тем же
интерпретатором, которым затем будет запущена программа.
Проверка связи:
import sys
import numpy as np
print("python:", sys.executable)
print("numpy:", np.__version__)
print("numpy file:", np.__file__)
Объявленные и зафиксированные зависимости
Есть два разных требования.
- Прямая зависимость нужна коду непосредственно, например NumPy.
- Транзитивная зависимость нужна прямой зависимости.
Ограничение numpy>=2 сообщает допустимый диапазон, но не гарантирует одинаковую
сборку завтра. Точная фиксация numpy==2.2.1 воспроизводимее, однако требует
осознанных обновлений. Для библиотеки обычно задают совместимые диапазоны, для
приложения или учебного окружения — lock-файл с точными версиями.
Минимальный requirements.txt:
numpy==2.2.1
pytest==8.3.4
Установка и контроль:
python -m pip install -r requirements.txt
python -m pip check
python -m pip freeze
freeze описывает текущее состояние, включая транзитивные пакеты. Это снимок,
а не обязательно хороший вручную поддерживаемый список прямых зависимостей.
Устройство вычислительного проекта
Практичная структура:
project/
├── README.md
├── pyproject.toml
├── src/
│ └── model.py
├── tests/
│ └── test_model.py
├── notebooks/
├── data/
│ ├── raw/
│ └── processed/
└── artifacts/
README.md описывает точные команды от чистого клона до результата. src/
содержит повторно используемую логику, tests/ — автоматические проверки,
notebooks/ — исследование, data/ — данные, artifacts/ — модели и отчёты.
Большие данные и сгенерированные результаты обычно не хранят в обычном Git.
Код не должен предполагать неизвестный текущий каталог. Путь относительно файла:
from pathlib import Path
PROJECT_ROOT = Path(__file__).resolve().parents[1]
config_path = PROJECT_ROOT / "config" / "train.json"
print(config_path)
Для команды запуска часто лучше явно передать путь аргументом. Тогда зависимость видна пользователю и тестируется отдельно.
Конфигурация и секреты
Конфигурация — параметры, которые законно меняются между запусками: путь к данным, размер батча, seed. Секреты — пароли, токены, ключи доступа. Секрет нельзя коммитить даже в «приватный» репозиторий: удаление из последнего коммита не удаляет его из истории.
Безопасный принцип:
- несекретные значения по умолчанию хранятся в версионируемом файле;
- секреты поступают из переменных окружения или хранилища секретов;
- пример
.env.exampleсодержит только имена переменных; - локальный
.envвключён в.gitignore.
import os
data_dir = os.getenv("DATA_DIR", "data/raw")
api_token = os.environ.get("API_TOKEN")
Разобранный пример: диагностика среды
Сценарий должен вывести версии и завершиться ошибкой, если пакет отсутствует.
from importlib.metadata import PackageNotFoundError, version
import platform
import sys
required = ["numpy", "pytest"]
print("Python:", sys.version.split()[0])
print("Executable:", sys.executable)
print("Platform:", platform.platform())
for package in required:
try:
print(f"{package}: {version(package)}")
except PackageNotFoundError:
raise SystemExit(f"Не установлен пакет {package!r}")
Такой отчёт полезен в журнале эксперимента. Он не заменяет lock-файл: два бинарных пакета одной версии теоретически могут отличаться сборкой или платформой.
Типичные ошибки и ограничения
- Установка в глобальный Python. Проекты начинают конфликтовать. Проверяйте
sys.executableи используйтеpython -m pip. - Коммит
.venv. Каталог велик, платформенно зависим и плохо переносим. Коммитьте спецификацию, а не установленную среду. - Только
pip freezeбез понимания. В снимке трудно отличить прямые зависимости. Поддерживайте декларацию и отдельную фиксацию. - Неограниченные версии. Свежий несовместимый релиз может сломать сборку.
- Абсолютные локальные пути. На другой машине их нет. Используйте параметры
запуска и
pathlib. - Скрытая системная зависимость. Драйвер GPU, компилятор и системная библиотека тоже входят в вычислительную среду и должны быть задокументированы.
Краткое резюме
- Воспроизводимость начинается с явного интерпретатора и изолированных пакетов.
- Окружение пересоздаётся; исходники и спецификации версионируются.
- Декларация зависимостей отвечает «что допустимо», lock-файл — «что установлено».
- Структура проекта отделяет код, тесты, данные, конфигурацию и результаты.
Связанные материалы
- Следующая глава:
02_git_reproducibility.md. - Практика:
../assignments/01_environment.md. - Термины:
glossary.md.