Представим, что мы начинаем работу с несколькими проектами. В каждом проекте могут быть разные наборы зависимостей. Еще более тяжелый случай: разные проекты могут иметь в зависимостях разные версии одной и той же библиотеки.
Чтобы предотвратить возможный конфликт, пакетный менеджер устанавливает зависимости проекта в его собственную директорию зависимостей - .venv. Но это не единственная функция этой директории.
Виртуальное окружение
Заглянем в директорию .venv:
tree .venv
# мы немного сократили вывод, оставив необходимое
.venv
├── bin
│ ├── flask
│ ├── pytest
│ ├── python -> /usr/bin/python3.13
│ ├── python3 -> python
│ └── python3.13 -> python
├── lib
│ └── python3.13
│ └── site-packages
│ ├── blinker
│ ├── click
│ ├── flask
│ ├── jinja2
│ ├── pytest
│ └── werkzeug
Здесь нам важны две директории: bin и lib. Вторая директория, lib/python3.XX/site-packages вам уже знакома - в ней установлены все зависимости проекта. Тогда как в директории .venv/bin лежит ссылка на интерпретатор Python. Для чего это нужно? Давайте сперва поставим библиотеку в наш проект.
uv add more-itertools
Создадим новый файл module.py, импортируем библиотеку и сделаем пару вызовов:
from more_itertools import sliced, substrings
subs = ["".join(s) for s in substrings("more")]
print(subs)
slices = list(sliced((1, 2, 3, 4, 5, 6, 7, 8), 3))
print(slices)
Запустим наш модуль с кодом:
python3 hexlet_hello_world/module.py
Traceback (most recent call last):
File "/hexlet_hello_world/module.py", line 1, in <module>
from more_itertools import sliced, substrings
ModuleNotFoundError: No module named 'more_itertools'
Почему же мы получили ошибку, ведь мы установили библиотеку в проект? Суть в том, что Python используется в операционной системе для запуска системных утилит. Зависимости этих утилит хранятся в /usr/lib/python3.XX/site-packages - директории общей для всех системы. И Python ищет зависимости в своих, системных директориях.
Но ставить зависимости проекта в системные директории нельзя, будут конфликты. Тогда мы можем поступить наоборот, и запустить Python из директории .venv нашего проекта. Для этого в ней и лежит ссылка на интерпретатор.
# указываем путь до интерпретатора внутри .venv
.venv/bin/python3 hexlet_hello_world/module.py
['m', 'o', 'r', 'e', 'mo', 'or', 're', 'mor', 'ore', 'more']
[(1, 2, 3), (4, 5, 6), (7, 8)]
Сочетание директории с зависимостями (lib/python3.XX/site-packages) и ссылки на интерпретатор (bin/python3) называется окружением. Окружение системного Python называют глобальным окружением, а окружение проекта локальным или чаще всего виртуальным окружением. Отсюда и название директории .vevn - Virtual Enviroment.
Но каждый раз вызывать код указывая полный путь до интерпретатора внутри .venv утомительно. Потому существует механизм подмены пути автоматически - активация окружения. При активации в переменную PATH
, подставляется путь до интерпретатора внутри .venv. Затем, когда мы вызовем команду python3
, то запустится Python внутри окружения. А когда мы закончим работу в окружении, останется лишь вернуть прежний путь, или еще говорят деактивировать окружение, чтобы система продолжила использовать системный Python с его библиотеками.
В действительности этот процесс приходится выполнять так часто, что пакетные менеджеры его автоматизируют.
uv run python3 hexlet_hello_world/module.py
['m', 'o', 'r', 'e', 'mo', 'or', 're', 'mor', 'ore', 'more']
[(1, 2, 3), (4, 5, 6), (7, 8)]
Команда uv run <команда>
активирует окружение, выполняет команду в нем и деактивирует его. Так вся работа с окружением скрыта от нас. В дальнейшем все команды запуска кода и утилит в проекте мы будем выполнять через uv run
.
Управление версиями Python
Разные проекты могут требовать не только разных версий библиотек, но и разных версий Python. При этом обновлять Python, установленный в системе, нельзя - могут сломаться системные утилиты. К счастью, механизм окружений позволяет управлять не только зависимостями, но и интерпретаторами. Вместо ссылки на системный Python можно указать ссылку на другую, отдельно скачанную версию.
uv
также автоматизирует этот процесс, по умолчанию uv
использует ссылку на системный интерпретатор, но для многих команд можно указать версию Python через флаг --python
:
# создает проект с указанной версией
uv init --python=3.13
# устанавливает проект с указанной версией
uv sync --python=3.13
# создает лишь окружение с указанной версией
uv venv --python=3.13
# запускает команду с указанной версией
uv run --python=3.13 <команда>
Если указанной версии нет в системе, то uv
скачает ее и будет использовать для текущего проекта. Системный Python это никак не затронет, так как интерпретатор проекта полностью изолирован.
Самостоятельная работа
- Создайте новый модуль и добавьте в него код из урока
- Запустите его командой
python3 <путь-до-модуля>
. Команда должна завершиться с ошибкойModule not found
- Запустите его вновь добавив к команде
uv run
, теперь команда должна выполниться без ошибок
Остались вопросы? Задайте их в разделе «Обсуждение»
Вам ответят команда поддержки Хекслета или другие студенты
Для полного доступа к курсу нужен базовый план
Базовый план откроет полный доступ ко всем курсам, упражнениям и урокам Хекслета, проектам и пожизненный доступ к теории пройденных уроков. Подписку можно отменить в любой момент.