Когда мы начинаем разрабатывать какой-либо Python-проект, который выходит за пределы обычных сценариев, мы обычно начинаем привлекать сторонние зависимости.
Если мы работаем с более крупным проектом, то мы должны задуматься о том, как мы можем эффективно управлять этими зависимостями. Причем, устанавливая зависимости, мы хотим оставаться внутри виртуальной среды. Таким образом, мы можем контролировать все, что там находится. Кроме того, это помогает избежать путаницы с нашей средой Python.
Для чего нам нужны виртуальные среды Python?
Для того, чтобы мы могли устанавливать пакеты в нашем проекте Python, нам нужен менеджер пакетов Pip. Причем, довольно часто в одном проекте могут устанавливаться несколько пакетов. А это может повлечь за собой некоторые проблемы, касающиеся версий пакетов, которые были установлены, и их зависимостей.
Когда мы используем в проекте pip install <package name>, мы устанавливаем пакет и его зависимости в глобальном пространстве имен Python. Таким образом, мы установим пакет для определенной версии Python, для которой мы настроили среду.
Мы можем узнать, где расположен данный каталог, следующим образом:
python3.7 -c "import sys; print('\n'.join(sys.path))"
/usr/lib/python27.zip
/usr/lib/python2.7
/usr/lib/python2.7/lib-dynload
/usr/lib/python2.7/site-packages
А если мы установим тот же пакет, но с помощью pip3 install <package name>, он будет установлен в отдельный каталог, где находится версия для Python 3. Мы можем изменить это следующим образом:
python2.7 -m pip install <package name>
Однако это не является решением нашей проблемы, связанной с установкой пакетов в масштабе системы, что может стать причиной других проблем:
- Разные проекты, которые используют разные версии одного и того же пакета, будут конфликтовать друг с другом
- Зависимости проекта могут конфликтовать с зависимостями системного уровня, а это, в свою очередь, может «сломать» всю систему
- Отсутствие возможности разработки многопользовательских проектов
- Сложность тестирования кода при наличии разных версий Python и библиотек
Для того, чтобы избежать этих проблем, Python-разработчики используют виртуальные среды. Такие среды для установки пакетов и зависимостей используют изолированное окружение (каталоги).
Как создать виртуальную среду?
Здесь нам понадобиться инструмент, который позволит нам использовать виртуальные среды Python. Инструмент, который мы будем использовать для того, чтобы их создавать, называется venv. Он является частью стандартной библиотеки Python в Python 3.3+.
Если бы мы использовать Python 2, то мы должны были бы устанавливать его самостоятельно. Это один из немногих пакетов, которые мы будет устанавливать на глобальном уровне.
python2 -m pip install virtualenv
Примечание: в рамках данной статьи мы будем больше говорить о venv и Python 3, поскольку он немного отличается от virtualenv. У них разные команды (не все), и в принципе сами инструменты работают «за кадром» по-разному.
Мы начнем с того, что создадим новый каталог, в которым мы будем работать с нашим проектом.
mkdir my-python-project && cd my-python-project
После чего мы создадим новую виртуальную среду:
python3 -m venv virtualenv
# creates a virtual environment called virtualenv, the name can be anything we want { # создаем виртуальную среду под названием virtualenv, название может быть абсолютно любым }
В каталоге, который мы только что создали, будет создан каталог под названием virtualenv. В нем будут папки bin, lib, include и файл конфигурации среды.
Все эти файлы гарантируют, что весь код Python будет выполняться в пределах данной среды. Таким образом, мы можем изолироваться от глобальной среды и избежать всех тех проблем, о которых мы говорили ранее.
Для того, чтобы мы могли воспользоваться этой средой, мы должны ее активировать. Это, в свою очередь, заменит вашу командную строку на текущее окружение.
$ source env/bin/activate
(virtualenv) $
Приглашение пользователя к действиям также можно считать показателем того, что виртуальная среда активна и код Python выполняется именно в ней.
Если мы находимся внутри нашей среды, то у нас нет доступа к общесистемным пакетам, и наоборот, если мы находится в системе, то у нас нет доступа к любым пакетам, которые были установлены внутри среды.
В рамках виртуальной среды по умолчанию устанавливаются только два пакета: pip и setuptools.
После того, как среда будет активирована, переменная пути изменится для того, чтобы можно было реализовать концепцию виртуальной среды.
После того, как мы закончим работать с виртуальной средой, и захотим перейти обратно в глобальную, мы можем воспользоваться командой деактивации:
(virtualenv) $ deactivate
$
Как управлять зависимостями в рамках среды?
Теперь, когда мы настроили наши виртуальные среды, мы не хотим, чтобы наши пакеты, которые мы установили с помощью pip, использовали другие среды. Мы хотим исключить нашу папку виртуальной среды и возобновить нашу работу уже в другой системе.
Это можно сделать с помощью файла requirements, который расположен в корневом каталоге нашего проекта.
Допустим, что в рамках нашей виртуальной среды мы установили Flask. Затем, если мы запустим pip freeze, то увидим список пакетов, которые мы установили, и их версии.
(virtualenv) $ pip freeze
Flask==1.1.2
Мы можем записать это все в файл requirements.txt для того, чтобы потом загрузить его в Git или поделиться им с другими людьми каким-либо образом.
(virtualenv) $ pip freeze > requirements.txt
Причем эту команду можно использовать и для обновления файла.
А потом, когда кто-то будет запускать наш проект на своем компьютере, ему нужно будет выполнить следующее:
$ cd copied-project/
$ python3 -m venv virtualenv/
$ python3 -m pip install -r requirements.txt
И все будет работать точно также, как работало в нашей системе.
Заключение
И вот, мы умеем управлять виртуальными средами Python, а, значит, по мере необходимости зависимостями и пакетами.