Виртуальные окружения (venv)
| Тип | модуль стандартной библиотеки |
|---|---|
| Язык | Python |
| Появился в | Python 3.3 (2012) |
| Стандарт | PEP 405 |
| Предшественник | virtualenv (2007) |
| Команда | python -m venv .venv |
| Альтернативы | virtualenv, conda, uv, Poetry |
| Документация | docs.python.org/3/library/venv |
Виртуальное окружение в Python — изолированный каталог со ссылкой на интерпретатор и собственным набором установленных пакетов. Каждый проект получает своё окружение, поэтому разные проекты могут использовать разные версии одних и тех же библиотек, не мешая друг другу и системному Python. Стандартный инструмент для их создания — модуль venv из стандартной библиотеки.
Зачем нужны
Без окружений все пакеты ставятся в одну общую папку site-packages. Это порождает типичные проблемы:
- проекту A нужна библиотека версии 1.x, проекту B — 2.x, а установить можно только одну;
- установка пакетов в системный Python может сломать утилиты операционной системы, написанные на Python;
- нельзя точно воспроизвести набор зависимостей на другой машине;
- для установки в системные каталоги нужны права администратора.
Окружение решает всё это: пакеты ставятся внутрь каталога проекта, а удалить окружение можно простым удалением папки.
История
Изолированные окружения появились как сторонний инструмент virtualenv, созданный Яном Бикингом в 2007 году. Подход оказался настолько востребованным, что поддержку встроили в сам интерпретатор: PEP 405 добавил модуль venv в Python 3.3 (2012).[2] virtualenv продолжает развиваться как более быстрая и гибкая альтернатива.[5]
В 2021 году PEP 668 ввёл понятие внешне управляемого окружения: дистрибутивы Linux могут пометить системный Python, и тогда pip install вне виртуального окружения завершается ошибкой externally-managed-environment.[3] Так поступают, например, Debian 12 и Ubuntu 23.04 и более новые версии. Это сделало виртуальные окружения фактически обязательными.
Использование
python3 -m venv .venv # создать окружение в папке .venv
source .venv/bin/activate # активировать (Linux, macOS)
.venv\Scripts\activate # активировать (Windows)
python -m pip install requests # пакет ставится внутрь .venv
deactivate # выйти из окружения
Активация лишь добавляет каталог bin окружения в начало переменной PATH (см. Переменные окружения) и меняет приглашение оболочки. Её можно не выполнять, а вызывать интерпретатор напрямую: .venv/bin/python script.py — так обычно делают в скриптах, cron и юнитах systemd.
Каталог .venv не добавляют в Git: вместо него в репозитории хранят список зависимостей (requirements.txt, pyproject.toml или файл блокировки), по которому окружение можно пересоздать.
Устройство
Окружение — обычная папка:[1]
.venv/
├── pyvenv.cfg # путь к базовому интерпретатору и версия
├── bin/ # python, pip, activate, консольные скрипты пакетов
└── lib/python3.X/site-packages/ # установленные пакеты
Файл pyvenv.cfg сообщает интерпретатору при запуске, что он находится в окружении. Внутри окружения sys.prefix указывает на .venv, а sys.base_prefix — на базовую установку Python; по их различию код может определить, что работает в окружении. Сам интерпретатор не копируется, а подключается символической ссылкой, поэтому окружение привязано к конкретному базовому Python и при его обновлении или переносе папки может сломаться — тогда его пересоздают.
Полезные параметры: --system-site-packages (видеть пакеты базовой установки), --upgrade-deps (обновить pip при создании), --prompt (имя в приглашении оболочки).
Альтернативы
| Инструмент | Особенность |
|---|---|
venv |
встроен в Python, без зависимостей |
| virtualenv | быстрее, поддерживает больше версий Python |
| uv | uv venv создаёт окружение за доли секунды, сам управляет версиями Python |
| Poetry, PDM, Hatch | окружение создаётся автоматически вместе с управлением зависимостями проекта |
| conda | окружения с пакетами не только Python (C-библиотеки, CUDA), популярна в науке о данных |
Для полной изоляции от операционной системы, включая системные библиотеки, применяют контейнеры (см. Docker); внутри образа виртуальное окружение часто всё равно используют, чтобы отделить приложение от системного Python.