# 01. Python-окружения, зависимости и устройство проекта > Изолируем интерпретатор и зависимости так, чтобы проект одинаково запускался сегодня, на другой машине и в автоматической проверке. ## Мотивация Python-программа зависит не только от исходного кода. Результат могут изменить версия Python, версии библиотек, операционная система, переменные окружения и рабочий каталог. Фраза «у меня работает» обычно означает, что часть этих условий осталась неописанной. Воспроизводимый проект делает условия явными. Это позволяет: - не смешивать зависимости разных проектов; - повторно собрать среду после поломки; - отличить ошибку кода от несовместимости версий; - передать проект без копирования локального окружения. ## Интуитивная модель Окружение — это отдельный набор инструментов для одного проекта. Интерпретатор Python играет роль станка, пакеты — насадок, а файл зависимостей — спецификации комплекта. Каталог `.venv` является расходным артефактом: его можно удалить и собрать снова. Удобно разделять четыре слоя: 1. **исходники** — то, что пишется и проверяется в Git; 2. **конфигурация** — объявленные зависимости и параметры запуска; 3. **окружение** — конкретно установленные пакеты; 4. **данные и результаты** — входы и полученные артефакты. ## Интерпретатор, пакет и импорт **Интерпретатор** исполняет байткод Python. Команда `python` выбирается через `PATH`; поэтому перед установкой пакетов важно проверить, какой именно Python запущен: ```python import sys print(sys.executable) print(sys.version) ``` **Модуль** — обычно один файл `.py`. **Пакет** — импортируемая директория модулей. **Дистрибутив** — устанавливаемая единица, известная менеджеру пакетов. Имя дистрибутива и имя импорта иногда различаются: устанавливается `scikit-learn`, а импортируется `sklearn`. Поиск при `import name` идёт по `sys.path`. В него входят каталог запуска, стандартная библиотека, установленные пакеты и явно добавленные пути. Изменение рабочего каталога может поэтому скрыть ошибку структуры проекта. ## Создание виртуального окружения Из корня проекта: ```text python -m venv .venv ``` Активация в PowerShell: ```text .\.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` запускается тем же интерпретатором, которым затем будет запущена программа. Проверка связи: ```python 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`: ```text numpy==2.2.1 pytest==8.3.4 ``` Установка и контроль: ```text python -m pip install -r requirements.txt python -m pip check python -m pip freeze ``` `freeze` описывает текущее состояние, включая транзитивные пакеты. Это снимок, а не обязательно хороший вручную поддерживаемый список прямых зависимостей. ## Устройство вычислительного проекта Практичная структура: ```text 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. Код не должен предполагать неизвестный текущий каталог. Путь относительно файла: ```python 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`. ```python import os data_dir = os.getenv("DATA_DIR", "data/raw") api_token = os.environ.get("API_TOKEN") ``` ## Разобранный пример: диагностика среды Сценарий должен вывести версии и завершиться ошибкой, если пакет отсутствует. ```python 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`](02_git_reproducibility.md). - Практика: [`../assignments/01_environment.md`](../assignments/01_environment.md). - Термины: [`glossary.md`](glossary.md).