Пакеты позволяют организовать модули в иерархическую структуру. Виртуальные окружения изолируют зависимости проектов друг от друга. Вместе они составляют основу управления Python-проектами.
Что такое пакет
Пакет -- это директория, содержащая модули Python и специальный файл __init__.py. Начиная с Python 3.3, существуют также namespace-пакеты без __init__.py, но классические пакеты с ним остаются стандартом.
myproject/
mypackage/
__init__.py
models.py
services.py
utils/
__init__.py
validators.py
formatters.py
Файл __init__.py
Этот файл выполняется при импорте пакета. Он может быть пустым или содержать код инициализации:
# mypackage/__init__.py
"""MyPackage — a utility library for data processing."""
__version__ = "1.0.0"
__author__ = "Developer"
# Re-export key classes for convenient access
from .models import User, Product
from .services import UserService
# Now users can do:
# from mypackage import User, UserService
Управление экспортом пакета
# mypackage/__init__.py
__all__ = ["User", "Product", "UserService"]
from .models import User, Product
from .services import UserService
# from mypackage import * — will only import User, Product, UserService
Namespace-пакеты (PEP 420)
Начиная с Python 3.3, директория без __init__.py может быть namespace-пакетом. Это позволяет распределять пакет по нескольким директориям:
# No __init__.py needed
# Python merges all directories with the same name
import mycompany.auth # from path A
import mycompany.billing # from path B
# Both work under the same namespace
На практике для обычных проектов всегда создавайте __init__.py.
Виртуальные окружения (venv)
Виртуальное окружение -- это изолированная копия Python-интерпретатора с собственным набором пакетов. Это решает проблему конфликтов зависимостей между проектами.
Создание и активация
# Create a virtual environment
python3 -m venv .venv
# Activate (macOS/Linux)
source .venv/bin/activate
# Activate (Windows)
.venv\Scripts\activate
# Deactivate when done
deactivate
Проверка активации
# Check which Python is active
which python
# /path/to/project/.venv/bin/python
# Check installed packages
pip list
Менеджер пакетов pip
pip -- стандартный менеджер пакетов Python, устанавливающий пакеты из PyPI (Python Package Index).
Основные команды
# Install a package
pip install requests
# Install specific version
pip install requests==2.31.0
# Install with version range
pip install "requests>=2.28,<3.0"
# Upgrade a package
pip install --upgrade requests
# Uninstall
pip uninstall requests
# Show package info
pip show requests
# List all installed packages
pip list
# List outdated packages
pip list --outdated
requirements.txt
Файл requirements.txt фиксирует зависимости проекта:
# Generate from current environment
pip freeze > requirements.txt
# Install all dependencies
pip install -r requirements.txt
Пример requirements.txt:
# requirements.txt — pinned versions for reproducibility
requests==2.31.0
pydantic==2.6.1
sqlalchemy==2.0.27
alembic==1.13.1
httpx==0.27.0
# Development dependencies (often in a separate file)
# requirements-dev.txt
pytest==8.0.2
mypy==1.8.0
ruff==0.3.0
Разделение зависимостей
# requirements.txt — production
requests==2.31.0
pydantic==2.6.1
# requirements-dev.txt — development
-r requirements.txt
pytest==8.0.2
mypy==1.8.0
ruff==0.3.0
black==24.2.0
# Install production deps
pip install -r requirements.txt
# Install all deps including dev
pip install -r requirements-dev.txt
pyproject.toml -- современный стандарт
pyproject.toml (PEP 518, PEP 621) -- единый файл конфигурации проекта, заменяющий setup.py, setup.cfg и requirements.txt:
# pyproject.toml
[project]
name = "myproject"
version = "1.0.0"
description = "A sample Python project"
requires-python = ">=3.12"
license = "MIT"
authors = [
{ name = "Developer", email = "[email protected]" }
]
dependencies = [
"requests>=2.31",
"pydantic>=2.6",
"sqlalchemy>=2.0",
]
[project.optional-dependencies]
dev = [
"pytest>=8.0",
"mypy>=1.8",
"ruff>=0.3",
]
[project.scripts]
myapp = "myproject.cli:main"
[build-system]
requires = ["setuptools>=70.0"]
build-backend = "setuptools.backends._legacy:_Backend"
uv -- быстрый менеджер пакетов
uv -- это современная замена pip и venv, написанная на Rust. Работает в 10-100 раз быстрее pip:
# Install uv
curl -LsSf https://astral.sh/uv/install.sh | sh
# Create a new project
uv init myproject
cd myproject
# Add dependencies
uv add requests pydantic
# Add dev dependencies
uv add --dev pytest mypy ruff
# Run a script
uv run python main.py
# Sync dependencies (install from lock file)
uv sync
# Create virtual environment explicitly
uv venv
uv.lock -- точная фиксация
uv автоматически создает uv.lock -- lock-файл с точными версиями всех зависимостей:
# uv.lock is created/updated automatically
uv add httpx
# Install exact versions from lock file
uv sync
# Update all dependencies
uv lock --upgrade
Структура проекта с uv
myproject/
pyproject.toml # Project configuration
uv.lock # Locked dependencies
.venv/ # Virtual environment
src/
myproject/
__init__.py
main.py
tests/
test_main.py
pip-tools -- промежуточный вариант
pip-tools предоставляет компиляцию requirements:
pip install pip-tools
# Write loose requirements
# requirements.in
# requests>=2.31
# pydantic>=2.6
# Compile to pinned versions
pip-compile requirements.in
# Install pinned versions
pip-sync requirements.txt
Сравнение инструментов
| Инструмент | Скорость | Lock-файл | Управление venv | pyproject.toml |
|---|---|---|---|---|
| pip + venv | Медленно | Нет | Вручную | Частично |
| pip-tools | Медленно | Да | Вручную | Нет |
| Poetry | Средне | Да | Автоматически | Да |
| uv | Быстро | Да | Автоматически | Да |
Практический пример
Создадим проект с нуля используя uv:
# Initialize project
uv init webapp
cd webapp
# Add dependencies
uv add fastapi uvicorn[standard] pydantic
# Add dev dependencies
uv add --dev pytest httpx mypy ruff
# Project structure
# webapp/
# pyproject.toml
# uv.lock
# src/
# webapp/
# __init__.py
# src/webapp/__init__.py
"""Web application package."""
__version__ = "0.1.0"
# src/webapp/main.py
from fastapi import FastAPI
app = FastAPI(title="WebApp", version="0.1.0")
@app.get("/health")
async def health() -> dict[str, str]:
"""Health check endpoint."""
return {"status": "ok"}
# Run the application
uv run uvicorn webapp.main:app --reload