ai_learning/modules/00_environment/notes/01_python_environments.md

11 KiB
Raw Blame History

01. Python-окружения, зависимости и устройство проекта

Изолируем интерпретатор и зависимости так, чтобы проект одинаково запускался сегодня, на другой машине и в автоматической проверке.

Мотивация

Python-программа зависит не только от исходного кода. Результат могут изменить версия Python, версии библиотек, операционная система, переменные окружения и рабочий каталог. Фраза «у меня работает» обычно означает, что часть этих условий осталась неописанной.

Воспроизводимый проект делает условия явными. Это позволяет:

  • не смешивать зависимости разных проектов;
  • повторно собрать среду после поломки;
  • отличить ошибку кода от несовместимости версий;
  • передать проект без копирования локального окружения.

Интуитивная модель

Окружение — это отдельный набор инструментов для одного проекта. Интерпретатор Python играет роль станка, пакеты — насадок, а файл зависимостей — спецификации комплекта. Каталог .venv является расходным артефактом: его можно удалить и собрать снова.

Удобно разделять четыре слоя:

  1. исходники — то, что пишется и проверяется в Git;
  2. конфигурация — объявленные зависимости и параметры запуска;
  3. окружение — конкретно установленные пакеты;
  4. данные и результаты — входы и полученные артефакты.

Интерпретатор, пакет и импорт

Интерпретатор исполняет байткод 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-файл — «что установлено».
  • Структура проекта отделяет код, тесты, данные, конфигурацию и результаты.

Связанные материалы