Виртуальные окружения и зависимости: venv, pip, pyproject, uv

⏱ 30 мин · 🧩 заданий: 5

Проблема

Проект А требует Django 4.2, проект Б — Django 5.1. Если ставить пакеты в системный Python, они будут мешать друг другу, а обновление для одного проекта сломает другой. Кроме того, в Linux системный Python использует сама ОС — ломать его нельзя.

Виртуальное окружение — изолированная папка со своим интерпретатором (ссылкой на него) и своим site-packages.

venv

python -m venv .venv               # создать окружение в папке .venv
source .venv/bin/activate          # активировать (Linux/macOS)
.venv\Scripts\activate             # активировать (Windows)
python -m pip install requests     # пакеты ставятся в .venv
deactivate                         # выйти

Что внутри:

.venv/ ├── pyvenv.cfg ← home = /usr/bin, version = 3.12.4 ├── bin/ (Scripts\ на Windows) │ ├── python → /usr/bin/python3.12 │ ├── pip │ └── activate └── lib/python3.12/site-packages/ ← сюда ставятся пакеты

«Активация» просто ставит .venv/bin первым в PATH. Без активации можно вызывать напрямую: .venv/bin/python script.py.

import sys
print("интерпретатор:", sys.executable)
print("prefix:", sys.prefix)
print("base_prefix:", sys.base_prefix)
print("в виртуальном окружении:", sys.prefix != sys.base_prefix)

pip

pip install requests                    # последняя версия
pip install "django>=4.2,<5"            # с ограничением версии
pip install -r requirements.txt         # из файла
pip install -e .                        # текущий проект в режиме разработки (editable)
pip install --upgrade requests
pip uninstall requests
pip list                                # что установлено
pip show requests                       # подробности и зависимости пакета
pip freeze > requirements.txt           # зафиксировать точные версии

Спецификаторы версий

Запись Значение
==2.31.0 ровно эта версия
>=2.31 не ниже
>=4.2,<5 диапазон
~=2.31 совместимая: >=2.31, ==2.*
!=1.25.0 кроме этой
==2.* любая 2.x

Семантическое версионирование

MAJOR.MINOR.PATCH, например 2.31.0:

  • PATCH — исправления ошибок, совместимо;
  • MINOR — новые возможности, совместимо;
  • MAJOR — несовместимые изменения.

Поэтому разумное ограничение для библиотеки — >=2.31,<3.

pyproject.toml

Единый файл конфигурации проекта (PEP 518, 621): метаданные, зависимости, настройки инструментов.

[project]
name = "myapp"
version = "0.1.0"
requires-python = ">=3.11"
dependencies = [
    "fastapi>=0.110",
    "sqlalchemy>=2.0,<3",
    "pydantic-settings>=2",
]

[project.optional-dependencies]
dev = ["pytest>=8", "ruff", "mypy"]

[project.scripts]
myapp = "myapp.cli:main"

[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"

[tool.ruff]
line-length = 100

[tool.pytest.ini_options]
testpaths = ["tests"]

pip install -e ".[dev]" поставит проект вместе с инструментами разработки.

Прямые зависимости и lock-файл

  • В pyproject.toml — прямые зависимости с диапазонами («нужна FastAPI не ниже 0.110»).
  • В lock-файле (uv.lock, poetry.lock, requirements.txt из pip freeze/pip-compile) — точные версии всех пакетов, включая зависимости зависимостей.

Lock-файл гарантирует, что на CI, у коллеги и в продакшене установится одно и то же. Для приложений его коммитят, для библиотек обычно нет (библиотека должна работать с диапазоном версий).

Современные инструменты

Инструмент Для чего
uv очень быстрая замена pip, venv, pip-tools, pipx и pyenv в одном (на Rust)
Poetry управление зависимостями, lock-файл, сборка и публикация
pipx установка CLI-утилит (black, httpie) в отдельные окружения
pyenv несколько версий Python на одной машине
conda окружения с не-Python зависимостями (data science)
uv init myapp && cd myapp      # создать проект с pyproject.toml
uv add fastapi                 # добавить зависимость (обновит pyproject и uv.lock)
uv add --dev pytest
uv run pytest                  # запустить в окружении проекта (создаст .venv сам)
uv sync                        # установить ровно то, что в uv.lock
uv python install 3.12         # поставить нужную версию Python

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

Секреты (пароли БД, API-ключи) и настройки, зависящие от окружения, не хранят в коде. Их передают через переменные окружения (принцип 12-factor app):

import os

os.environ["DATABASE_URL"] = "postgresql://user:pass@localhost/shop"   # обычно задаётся снаружи
db_url = os.environ["DATABASE_URL"]             # KeyError, если не задана — и это хорошо
debug = os.getenv("DEBUG", "false").lower() == "true"
workers = int(os.getenv("WORKERS", "4"))
print(db_url, debug, workers)

Локально переменные кладут в файл .env (он в .gitignore!) и загружают через python-dotenv или pydantic-settings. В репозиторий коммитят .env.example с пустыми значениями.

.gitignore для Python

.venv/
__pycache__/
*.pyc
.env
.pytest_cache/
.mypy_cache/
.ruff_cache/
dist/
build/
*.egg-info/
.coverage
htmlcov/

Вопрос на собеседовании

«Как вы управляете зависимостями?» — Виртуальное окружение на проект; прямые зависимости в pyproject.toml с диапазонами версий; lock-файл с точными версиями для воспроизводимости (uv/Poetry/pip-tools); отдельная группа dev-зависимостей; регулярное обновление и проверка уязвимостей (pip-audit, Dependabot).

Итог

  • Виртуальное окружение изолирует пакеты проекта: python -m venv .venv.
  • python -m pip install, спецификаторы версий, семантическое версионирование.
  • pyproject.toml — конфигурация проекта; lock-файл — точные версии для воспроизводимости.
  • uv — быстрый современный инструмент «всё в одном».
  • Секреты — в переменных окружения, .env не коммитить.

Практика решено 0 из 5

Вы не вошли — ответы проверяются, но прогресс не сохранится. Войти или зарегистрироваться.
Задание 1 Заполнить таблицу

Какие версии подходят под спецификатор?

подходитне подходит
Django>=4.2,<5.0 — версия 4.2.11
Django>=4.2,<5.0 — версия 5.0
requests~=2.31 — версия 2.32.3
requests~=2.31 — версия 3.0
pydantic==2.* — версия 2.7.1
numpy!=1.25.0 — версия 1.25.0
Отметьте ячейку — «+», пустая — «−».
Задание 2 Один вариант ответа

Зачем нужно виртуальное окружение?

Задание 3 Один вариант ответа

Чем requirements.txt, полученный через pip freeze, отличается от списка зависимостей в pyproject.toml?

Задание 4 Один вариант ответа

Версия библиотеки изменилась с 2.4.1 на 3.0.0. Что это означает по семантическому версионированию?

Задание 5 Несколько вариантов

Что не нужно коммитить в Git?

Войдите, чтобы отмечать пройденные уроки.