# Виртуальные окружения { #virtual-environments } При работе с проектами на Python рекомендуется использовать **виртуальное окружение** (или похожий механизм), чтобы изолировать пакеты, которые вы устанавливаете для каждого проекта. /// info | Дополнительная информация Если вы уже знакомы с виртуальными окружениями, знаете, как их создавать и использовать, вы можете пропустить этот раздел. 🤓 /// /// tip | Подсказка **Виртуальное окружение** — это не то же самое, что **переменная окружения**. **Переменная окружения** — это переменная в системе, которую могут использовать программы. **Виртуальное окружение** — это директория с файлами внутри. /// /// info | Дополнительная информация На этой странице вы узнаете, как пользоваться **виртуальными окружениями** и как они работают. Если вы готовы начать использовать **инструмент, который управляет всем** за вас (включая установку Python), попробуйте uv. /// ## Создание проекта { #create-a-project } Сначала создайте директорию для вашего проекта. Обычно я создаю папку с именем `code` в моем домашнем каталоге. А внутри неё создаю отдельную директорию для каждого проекта.
```console // Перейдите в домашний каталог $ cd // Создайте директорию для всех ваших проектов с кодом $ mkdir code // Перейдите в эту директорию code $ cd code // Создайте директорию для этого проекта $ mkdir awesome-project // Перейдите в директорию проекта $ cd awesome-project ```
## Создание виртуального окружения { #create-a-virtual-environment } Когда вы начинаете работать над Python‑проектом **впервые**, создайте виртуальное окружение **внутри вашего проекта**. /// tip | Подсказка Делать это нужно **один раз на проект**, не каждый раз, когда вы работаете. /// //// tab | `venv` Для создания виртуального окружения вы можете использовать модуль `venv`, который поставляется вместе с Python.
```console $ python -m venv .venv ```
/// details | Что делает эта команда? * `python`: использовать программу под названием `python` * `-m`: вызвать модуль как скрипт, далее мы укажем, какой модуль вызвать * `venv`: использовать модуль `venv`, который обычно устанавливается вместе с Python * `.venv`: создать виртуальное окружение в новой директории `.venv` /// //// //// tab | `uv` Если у вас установлен `uv`, вы можете использовать его для создания виртуального окружения.
```console $ uv venv ```
/// tip | Подсказка По умолчанию `uv` создаст виртуальное окружение в директории с именем `.venv`. Но вы можете переопределить это, передав дополнительный аргумент с именем директории. /// //// Эта команда создаст новое виртуальное окружение в директории `.venv`. /// details | `.venv` или другое имя? Вы можете создать виртуальное окружение в другой директории, но по соглашению его называют `.venv`. /// ## Активация виртуального окружения { #activate-the-virtual-environment } Активируйте новое виртуальное окружение, чтобы все команды Python и устанавливаемые пакеты использовали именно его. /// tip | Подсказка Делайте это **каждый раз**, когда вы начинаете **новую сессию терминала** для работы над проектом. /// //// tab | Linux, macOS
```console $ source .venv/bin/activate ```
//// //// tab | Windows PowerShell
```console $ .venv\Scripts\Activate.ps1 ```
//// //// tab | Windows Bash Или если вы используете Bash для Windows (например, Git Bash):
```console $ source .venv/Scripts/activate ```
//// /// tip | Подсказка Каждый раз, когда вы устанавливаете **новый пакет** в это окружение, **активируйте** окружение снова. Это гарантирует, что если вы используете **программу терминала (CLI)**, установленную этим пакетом, вы будете использовать именно ту, что из вашего виртуального окружения, а не какую‑то глобально установленную, возможно другой версии, чем вам нужна. /// ## Проверка, что виртуальное окружение активно { #check-the-virtual-environment-is-active } Проверьте, что виртуальное окружение активно (предыдущая команда сработала). /// tip | Подсказка Это **необязательно**, но это хороший способ **проверить**, что всё работает как ожидается и вы используете запланированное виртуальное окружение. /// //// tab | Linux, macOS, Windows Bash
```console $ which python /home/user/code/awesome-project/.venv/bin/python ```
Если отображается исполняемый файл `python` по пути `.venv/bin/python` внутри вашего проекта (в нашем случае `awesome-project`), значит всё сработало. 🎉 //// //// tab | Windows PowerShell
```console $ Get-Command python C:\Users\user\code\awesome-project\.venv\Scripts\python ```
Если отображается исполняемый файл `python` по пути `.venv\Scripts\python` внутри вашего проекта (в нашем случае `awesome-project`), значит всё сработало. 🎉 //// ## Обновление `pip` { #upgrade-pip } /// tip | Подсказка Если вы используете `uv`, то для установки вы будете использовать его вместо `pip`, поэтому обновлять `pip` не нужно. 😎 /// Если для установки пакетов вы используете `pip` (он идёт по умолчанию вместе с Python), вам стоит **обновить** его до последней версии. Многие экзотические ошибки при установке пакетов решаются простым предварительным обновлением `pip`. /// tip | Подсказка Обычно это делается **один раз**, сразу после создания виртуального окружения. /// Убедитесь, что виртуальное окружение активно (см. команду выше) и запустите:
```console $ python -m pip install --upgrade pip ---> 100% ```
/// tip | Подсказка Иногда при попытке обновить pip вы можете получить ошибку **`No module named pip`**. Если это произошло, установите и обновите pip с помощью команды ниже:
```console $ python -m ensurepip --upgrade ---> 100% ```
Эта команда установит pip, если он ещё не установлен, а также гарантирует, что установленная версия pip будет не старее, чем версия, доступная в `ensurepip`. /// ## Добавление `.gitignore` { #add-gitignore } Если вы используете **Git** (а вам стоит его использовать), добавьте файл `.gitignore`, чтобы исключить из Git всё, что находится в вашей `.venv`. /// tip | Подсказка Если вы использовали `uv` для создания виртуального окружения, он уже сделал это за вас — можно пропустить этот шаг. 😎 /// /// tip | Подсказка Сделайте это **один раз**, сразу после создания виртуального окружения. ///
```console $ echo "*" > .venv/.gitignore ```
/// details | Что делает эта команда? * `echo "*"`: «напечатать» в терминале текст `*` (следующая часть немного меняет поведение) * `>`: всё, что команда слева от `>` выводит в терминал, вместо печати нужно записать в файл, указанный справа от `>` * `.gitignore`: имя файла, в который нужно записать текст А `*` в Git означает «всё». То есть будет игнорироваться всё в директории `.venv`. Эта команда создаст файл `.gitignore` со следующим содержимым: ```gitignore * ``` /// ## Установка пакетов { #install-packages } После активации окружения вы можете устанавливать в него пакеты. /// tip | Подсказка Сделайте это **один раз** при установке или обновлении пакетов, необходимых вашему проекту. Если вам нужно обновить версию или добавить новый пакет, вы **сделаете это снова**. /// ### Установка пакетов напрямую { #install-packages-directly } Если вы торопитесь и не хотите объявлять зависимости проекта в отдельном файле, вы можете установить их напрямую. /// tip | Подсказка Очень хорошая идея — указать используемые вашим проектом пакеты и их версии в файле (например, `requirements.txt` или `pyproject.toml`). /// //// tab | `pip`
```console $ pip install "fastapi[standard]" ---> 100% ```
//// //// tab | `uv` Если у вас установлен `uv`:
```console $ uv pip install "fastapi[standard]" ---> 100% ```
//// ### Установка из `requirements.txt` { #install-from-requirements-txt } Если у вас есть `requirements.txt`, вы можете использовать его для установки пакетов. //// tab | `pip`
```console $ pip install -r requirements.txt ---> 100% ```
//// //// tab | `uv` Если у вас установлен `uv`:
```console $ uv pip install -r requirements.txt ---> 100% ```
//// /// details | `requirements.txt` `requirements.txt` с некоторыми пакетами может выглядеть так: ```requirements.txt fastapi[standard]==0.113.0 pydantic==2.8.0 ``` /// ## Запуск вашей программы { #run-your-program } После активации виртуального окружения вы можете запустить свою программу, и она будет использовать Python из вашего виртуального окружения вместе с установленными там пакетами.
```console $ python main.py Hello World ```
## Настройка вашего редактора кода { #configure-your-editor } Скорее всего, вы будете использовать редактор кода. Убедитесь, что вы настроили его на использование того же виртуального окружения, которое вы создали (обычно он определяет его автоматически), чтобы получить автозавершение и подсветку ошибок. Например: * VS Code * PyCharm /// tip | Подсказка Обычно это нужно сделать только **один раз**, при создании виртуального окружения. /// ## Деактивация виртуального окружения { #deactivate-the-virtual-environment } Когда закончите работу над проектом, вы можете **деактивировать** виртуальное окружение.
```console $ deactivate ```
Таким образом, при запуске `python` он не будет пытаться запускаться из этого виртуального окружения с установленными там пакетами. ## Готово к работе { #ready-to-work } Теперь вы готовы начать работать над своим проектом. /// tip | Подсказка Хотите понять, что это всё было выше? Продолжайте читать. 👇🤓 /// ## Зачем нужны виртуальные окружения { #why-virtual-environments } Чтобы работать с FastAPI, вам нужно установить Python. После этого вам нужно будет **установить** FastAPI и другие **пакеты**, которые вы хотите использовать. Для установки пакетов обычно используют команду `pip`, которая идет вместе с Python (или альтернативные инструменты). Тем не менее, если просто использовать `pip` напрямую, пакеты будут установлены в **глобальное окружение Python** (глобально установленный Python). ### Проблема { #the-problem } Так в чём проблема установки пакетов в глобальное окружение Python? Со временем вы, вероятно, будете писать много разных программ, зависящих от **разных пакетов**. И некоторые из ваших проектов будут зависеть от **разных версий** одного и того же пакета. 😱 Например, вы можете создать проект `philosophers-stone`, который зависит от пакета **`harry` версии `1`**. Значит, нужно установить `harry`. ```mermaid flowchart LR stone(philosophers-stone) -->|requires| harry-1[harry v1] ``` Затем вы создаёте другой проект `prisoner-of-azkaban`, который тоже зависит от `harry`, но ему нужен **`harry` версии `3`**. ```mermaid flowchart LR azkaban(prisoner-of-azkaban) --> |requires| harry-3[harry v3] ``` Проблема в том, что если устанавливать пакеты глобально (в глобальное окружение), а не в локальное **виртуальное окружение**, вам придётся выбирать, какую версию `harry` установить. Если вы хотите запустить `philosophers-stone`, сначала нужно установить `harry` версии `1`, например так:
```console $ pip install "harry==1" ```
Тогда у вас в глобальном окружении Python будет установлен `harry` версии `1`: ```mermaid flowchart LR subgraph global[global env] harry-1[harry v1] end subgraph stone-project[philosophers-stone project] stone(philosophers-stone) -->|requires| harry-1 end ``` Но если затем вы захотите запустить `prisoner-of-azkaban`, вам нужно будет удалить `harry` версии `1` и установить `harry` версии `3` (или просто установка версии `3` автоматически удалит версию `1`).
```console $ pip install "harry==3" ```
В итоге у вас будет установлен `harry` версии `3` в глобальном окружении Python. А если вы снова попробуете запустить `philosophers-stone`, есть шанс, что он **не будет работать**, так как ему нужен `harry` версии `1`. ```mermaid flowchart LR subgraph global[global env] harry-1[harry v1] style harry-1 fill:#ccc,stroke-dasharray: 5 5 harry-3[harry v3] end subgraph stone-project[philosophers-stone project] stone(philosophers-stone) -.-x|⛔️| harry-1 end subgraph azkaban-project[prisoner-of-azkaban project] azkaban(prisoner-of-azkaban) --> |requires| harry-3 end ``` /// tip | Подсказка В Python-пакетах часто стараются изо всех сил **избегать ломающих изменений** в **новых версиях**, но лучше действовать осторожно: устанавливать новые версии осознанно и тогда, когда вы можете прогнать тесты и убедиться, что всё работает корректно. /// Теперь представьте то же самое с **многими** другими **пакетами**, от которых зависят все ваши **проекты**. Этим очень сложно управлять. И вы, скорее всего, в какой‑то момент будете запускать проекты с **несовместимыми версиями** пакетов и не понимать, почему что‑то не работает. Кроме того, в зависимости от ОС (например, Linux, Windows, macOS), она может поставляться с уже установленным Python. И тогда, вероятно, в системе уже есть предустановленные пакеты определённых версий, **нужные вашей системе**. Если вы устанавливаете пакеты в глобальное окружение Python, вы можете в итоге **сломать** некоторые системные программы. ## Куда устанавливаются пакеты { #where-are-packages-installed } Когда вы устанавливаете Python, на вашем компьютере создаются некоторые директории с файлами. Часть этих директорий отвечает за хранение всех устанавливаемых вами пакетов. Когда вы запускаете:
```console // Не запускайте это сейчас, это просто пример 🤓 $ pip install "fastapi[standard]" ---> 100% ```
Будет загружен сжатый файл с кодом FastAPI, обычно с PyPI. Также будут **загружены** файлы для других пакетов, от которых зависит FastAPI. Затем все эти файлы будут **распакованы** и помещены в директорию на вашем компьютере. По умолчанию они попадут в директорию из вашей установки Python — это **глобальное окружение**. ## Что такое виртуальные окружения { #what-are-virtual-environments } Решение проблемы с пакетами в глобальном окружении — использовать **виртуальное окружение для каждого проекта**, над которым вы работаете. Виртуальное окружение — это **директория**, очень похожая на глобальную, куда вы можете устанавливать пакеты для конкретного проекта. Таким образом, у каждого проекта будет своё виртуальное окружение (директория `.venv`) со своими пакетами. ```mermaid flowchart TB subgraph stone-project[philosophers-stone project] stone(philosophers-stone) --->|requires| harry-1 subgraph venv1[.venv] harry-1[harry v1] end end subgraph azkaban-project[prisoner-of-azkaban project] azkaban(prisoner-of-azkaban) --->|requires| harry-3 subgraph venv2[.venv] harry-3[harry v3] end end stone-project ~~~ azkaban-project ``` ## Что означает активация виртуального окружения { #what-does-activating-a-virtual-environment-mean } Когда вы активируете виртуальное окружение, например так: //// tab | Linux, macOS
```console $ source .venv/bin/activate ```
//// //// tab | Windows PowerShell
```console $ .venv\Scripts\Activate.ps1 ```
//// //// tab | Windows Bash Или если вы используете Bash для Windows (например, Git Bash):
```console $ source .venv/Scripts/activate ```
//// Эта команда создаст или изменит некоторые [переменные окружения](environment-variables.md){.internal-link target=_blank}, которые будут доступны для следующих команд. Одна из таких переменных — `PATH`. /// tip | Подсказка Вы можете узнать больше о переменной окружения `PATH` в разделе [Переменные окружения](environment-variables.md#path-environment-variable){.internal-link target=_blank}. /// Активация виртуального окружения добавляет его путь `.venv/bin` (на Linux и macOS) или `.venv\Scripts` (на Windows) в переменную окружения `PATH`. Предположим, что до активации окружения переменная `PATH` выглядела так: //// tab | Linux, macOS ```plaintext /usr/bin:/bin:/usr/sbin:/sbin ``` Это означает, что система будет искать программы в: * `/usr/bin` * `/bin` * `/usr/sbin` * `/sbin` //// //// tab | Windows ```plaintext C:\Windows\System32 ``` Это означает, что система будет искать программы в: * `C:\Windows\System32` //// После активации виртуального окружения переменная `PATH` будет выглядеть примерно так: //// tab | Linux, macOS ```plaintext /home/user/code/awesome-project/.venv/bin:/usr/bin:/bin:/usr/sbin:/sbin ``` Это означает, что теперь система в первую очередь будет искать программы в: ```plaintext /home/user/code/awesome-project/.venv/bin ``` прежде чем искать в других директориях. Поэтому, когда вы введёте в терминале `python`, система найдёт программу Python по пути ```plaintext /home/user/code/awesome-project/.venv/bin/python ``` и использует именно её. //// //// tab | Windows ```plaintext C:\Users\user\code\awesome-project\.venv\Scripts;C:\Windows\System32 ``` Это означает, что теперь система в первую очередь будет искать программы в: ```plaintext C:\Users\user\code\awesome-project\.venv\Scripts ``` прежде чем искать в других директориях. Поэтому, когда вы введёте в терминале `python`, система найдёт программу Python по пути ```plaintext C:\Users\user\code\awesome-project\.venv\Scripts\python ``` и использует именно её. //// Важная деталь: путь к виртуальному окружению будет добавлен в самое **начало** переменной `PATH`. Система найдёт его **раньше**, чем любой другой установленный Python. Таким образом, при запуске `python` будет использоваться Python **из виртуального окружения**, а не какой‑то другой `python` (например, из глобального окружения). Активация виртуального окружения также меняет ещё несколько вещей, но это — одна из важнейших. ## Проверка виртуального окружения { #checking-a-virtual-environment } Когда вы проверяете, активно ли виртуальное окружение, например, так: //// tab | Linux, macOS, Windows Bash
```console $ which python /home/user/code/awesome-project/.venv/bin/python ```
//// //// tab | Windows PowerShell
```console $ Get-Command python C:\Users\user\code\awesome-project\.venv\Scripts\python ```
//// Это означает, что будет использоваться программа `python` **из виртуального окружения**. На Linux и macOS используется `which`, а в Windows PowerShell — `Get-Command`. Как работает эта команда: она проходит по переменной окружения `PATH`, идя **по каждому пути по порядку**, и ищет программу с именем `python`. Как только находит — **показывает путь** к этой программе. Самое важное — при вызове `python` именно этот «`python`» и будет выполняться. Так вы можете подтвердить, что находитесь в правильном виртуальном окружении. /// tip | Подсказка Легко активировать одно виртуальное окружение, получить один Python, а затем **перейти к другому проекту**. И второй проект **не будет работать**, потому что вы используете **не тот Python**, из виртуального окружения другого проекта. Полезно уметь проверить, какой именно `python` используется. 🤓 /// ## Зачем деактивировать виртуальное окружение { #why-deactivate-a-virtual-environment } Например, вы работаете над проектом `philosophers-stone`, **активируете виртуальное окружение**, устанавливаете пакеты и работаете с ним. Затем вы хотите поработать над **другим проектом** `prisoner-of-azkaban`. Вы переходите в этот проект:
```console $ cd ~/code/prisoner-of-azkaban ```
Если вы не деактивируете виртуальное окружение `philosophers-stone`, при запуске `python` в терминале он попытается использовать Python из `philosophers-stone`.
```console $ cd ~/code/prisoner-of-azkaban $ python main.py // Error importing sirius, it's not installed 😱 Traceback (most recent call last): File "main.py", line 1, in import sirius ```
Но если вы деактивируете виртуальное окружение и активируете новое для `prisoner-of-askaban`, тогда при запуске `python` он будет использовать Python из виртуального окружения `prisoner-of-azkaban`.
```console $ cd ~/code/prisoner-of-azkaban // Вам не нужно находиться в старой директории, чтобы деактивировать окружение, вы можете сделать это где угодно, даже после перехода в другой проект 😎 $ deactivate // Активируйте виртуальное окружение в prisoner-of-azkaban/.venv 🚀 $ source .venv/bin/activate // Теперь при запуске python он найдёт пакет sirius, установленный в этом виртуальном окружении ✨ $ python main.py I solemnly swear 🐺 ```
## Альтернативы { #alternatives } Это простое руководство, чтобы вы начали и поняли, как всё работает **под капотом**. Существует много **альтернатив** для управления виртуальными окружениями, зависимостями (requirements), проектами. Когда вы будете готовы и захотите использовать инструмент для **управления всем проектом** — зависимостями пакетов, виртуальными окружениями и т. п., я бы предложил попробовать uv. `uv` может многое: * **Устанавливать Python**, включая разные версии * Управлять **виртуальным окружением** ваших проектов * Устанавливать **пакеты** * Управлять **зависимостями и версиями** пакетов вашего проекта * Обеспечивать наличие **точного** набора пакетов и версий к установке, включая их зависимости, чтобы вы были уверены, что сможете запускать проект в продакшн точно так же, как и на компьютере при разработке — это называется **locking** * И многое другое ## Заключение { #conclusion } Если вы прочитали и поняли всё это, теперь **вы знаете гораздо больше** о виртуальных окружениях, чем многие разработчики. 🤓 Знание этих деталей, скорее всего, пригодится вам в будущем, когда вы будете отлаживать что‑то сложное: вы будете понимать, **как всё работает под капотом**. 😎