Здесь вы узнаете, как создавать, управлять и использовать виртуальную среду для своих проектов на Python, как используют разные версии Python для выполнения вашего проекта. Мы также рассмотрим, как хранятся и разрешаются зависимости Python.

Содержание

Зачем нужна виртуальная среда?    ↑

Python, как и большинство других современных языков программирования, имеет свой собственный уникальный способ загрузки, хранения и разрешения пакетов (или модулей). Хотя в этом есть свои преимущества и есть несколько интересных решений для хранения и описания зависимостей между пакетами, до сих пор это может приводить к некоторым проблемам, особенно, в части того, как и где хранятся пакеты.

Есть несколько разных мест, где эти пакеты могут быть установлены в вашей системе. Например, большинство системных пакетов хранятся в дочернем каталоге, который описан в sys.prefix.

В Mac OS X вы можете легко найти, где sys.prefix указывает на использование оболочки Python:

>>> import sys
>>> sys.prefix
'/System/Library/Frameworks/Python.framework/Versions/3.5'

Теме этой статьи более соответствуют сторонние пакеты, установленные с использованием easy_install или pip, которые, обычно, размещаются в одном из каталогов, на который указывает site.getsitepackages:

>>> import site
>>> site.getsitepackages()
[
  '/System/Library/Frameworks/Python.framework/Versions/3.5/Extras/lib/python',
  '/Library/Python/3.5/site‑packages'
]

Итак, почему эти маленькие детали имеют значение?

Это важно знать, потому что по умолчанию каждый проект в вашей системе будет использовать эти же каталоги для хранения и извлечения пакетов (сторонних библиотек), используемых в проекте. На первый взгляд это может показаться не таким уж большим делом? Однако, это не так для системных пакетов, пакетов, являющихся частью стандартной библиотеки Python.

Рассмотрим следующую ситуацию, когда есть два проекта: ProjectA и ProjectB, и оба зависят от одной и той же библиотеки, ProjectC. Проблема становится очевидной, когда нам нужны разные версии ProjectC. Возможно, ProjectA должен использовать версию 1.0.0, в то время как ProjectB, например, требует более свежей версия 2.0.0.

Это реальная проблема, поскольку Python не может различить версии в каталоге site‑packages. Таким образом, и v1.0.0, и v2.0.0 будут находиться в одном и том же каталоге с одинаковыми именами:

/System/Library/Frameworks/Python.framework/Versions/3.5/Extras/lib/python/ProjectC

Поскольку проекты идентифицируются только именами, нет различий между версиями. Таким образом, оба проекта, ProjectA и ProjectB, должны будут использовать одну и ту же версию, что во многих случаях недопустимо.

Здесь в игру вступает virtualenv и venv

Что есть виртуальная среда?    ↑

По своей сути, основная цель виртуальной среды Python — создание изолированного окружения проектов Python. Это означает, что каждый проект может иметь свои собственные зависимости, независимо от того, какие зависимости есть у каждого соседнего проекта.

В приведенном выше небольшом примере нам просто нужно создать отдельную виртуальную среду как для ProjectA, так и для ProjectB, и тогда всё будет в порядке. В каждой среде, в свою очередь, можно определить свою, требуемую именно для него, зависимость версии ProjectC.

Самое замечательное заключается в том, что количество окружений, которые можно использовать, не ограничено, поскольку это просто каталоги, содержащие свои сценарии. Кроме того, они легко создаются с помощью инструментов командной строки virtualenv или pyenv.

Использование виртуальной среды    ↑

Для начала, если у вас не Python 3, нужно установить инструмент virtualenv, используя pip:

$ pip install virtualenv

Если у вас Python 3, то уже должен быть установлен модуль venv из стандартной библиотеки.

Примечание

Далее, будем считать, что у вас более новый инструмент venv, поскольку в части фактических команд мало различий между ним и virtualenv. Хотя, в действительности это очень разные инструменты.

Для начала создайте новый каталог:

$ mkdir python-virtual-environments && cd python-virtual-environments

Создайте новую виртуальную среду в этом каталоге:

# Python 2:
$ virtualenv env

# Python 3
$ python3 -m venv env

Примечание:

По умолчанию новая среда не содержит никаких ваших пакетов.

В venv Python 3 можно выбирать конкретную версию интерпретатора Python 3, которая должна использоваться при создании виртуальной среды, что позволяет избежать путаницы относительно того, на какой установке Python основана новая среда.

Начиная с Python 3.3 до 3.4, рекомендуемый способ создания виртуальной среды состоял в том, чтобы использовать инструмент командной строки pyvenv, который также по умолчанию включен в установку Python 3. Но в 3.6 и выше необходимо записывать python3 -m venv.

В приведенном выше примере эта команда создает каталог с именем env, имеющий следующую структуру:

├── bin
│   ├── activate
│   ├── activate.csh
│   ├── activate.fish
│   ├── easy_install
│   ├── easy_install-3.5
│   ├── pip
│   ├── pip3 
│   ├── pip3.5
│   ├── python -> python3.5
│   ├── python3 -> python3.5
│   └── python3.5 ->/Library/Frameworks/Python.framework/Versions/3.5/bin/python3.5
├── include
├── lib
│   └── python3.5
│       └── site‑packages
└── pyvenv.cfg

Вот что содержит каждая папка:

  • bin: файлы, которые используют виртуальную среду;
  • include: C-заголовки предварительно скомпилированных пакетов Python;
  • lib: копия версии Python вместе с папкой site‑packages, в которой находятся все установленные зависимости вашего проекта

Кроме того, есть символическая ссылка или копии различных инструментов Python, а также сами исполняемые файлы Python. Эти файлы обеспечивают выполнение команд и всего вашего кода в контексте текущей среды, обеспечивая изоляцию от глобальной среды. Более подробно об этом в следующем разделе.

Более интересными являются сценарии активации в каталоге bin. Эти сценарии по умолчанию используются для настройки оболочки на использование исполняемого файла среды Python и его site‑packages.

Чтобы использовать пакеты/ресурсы этой среды изолированно, необходимо «активировать» ее. Для этого просто запустите следующее:

$ source env/bin/activate
(env) $

Обратите внимание, что теперь к приглашению добавляется имя среды (в нашем случае env). Это показывает, что env в настоящее время активна и будет использовант тот исполняемый файл python, только те пакеты, которые соответствуют настройкам среды.

Чтобы показать изоляцию пакета в действии, для примера, можно использовать модуль bcrypt. Допустим, bcrypt установлено в масштабе всей системы, но не в нашей виртуальной среде.

Прежде чем мы протестируем это, нам нужно вернуться к «системному» контексту, выполнив deactivate:

(env) $ deactivate
$

Теперь ваша оболочка вернулась в нормальное состояние, а команда python ссылается на глобальную установку Python. Не забывайте делать это всякий раз, когда вы закончили работу в конкретной виртуальной среде.

Теперь установите bcrypt и используйте его для хэширования пароля:

$ pip -q install bcrypt
$ python -c "import bcrypt; print(bcrypt.hashpw('password'.encode('utf-8'), bcrypt.gensalt()))"
$2b$12$vWa/VSvxxyQ9d.WGgVTdrell515Ctux36LCga8nM5QTW0.4w8TXXi

Вот что произойдет, если мы попробуем ту же команду при активации виртуальной среды:

$ source env/bin/activate(env) 
$ python -c "import bcrypt; print(bcrypt.hashpw('password'.encode('utf-8'), bcrypt.gensalt()))"

Traceback (most recent call last):
  File "", line 1, in 
ImportError: No module named 'bcrypt'

Как видите, поведение команды python -c "import bcrypt ..." изменяется после вызова source env/bin/activ.

В первом случае у нас есть bcrypt, а во втором нет. Это то самое разделение, которое нам нужно от виртуальных сред.

Как работает виртуальная среда?    ↑

Что именно означает «активировать» среду? То, что «под капотом», может быть очень важным для разработчика, особенно, тогда, когда необходимо понять, что есть среда выполнения, разрешение зависимостей и так далее.

Чтобы объяснить, как это работает, давайте сначала проверим расположение различных исполняемых файлов python. При «деактивированной» среде выполните следующее:

$ which python
/usr/bin/python

Теперь активируйте её и снова введите команду:

$ source env/bin/activate (env) 
$ which python
/Users/michaelherman/python-virtual-environments/env/bin/python

После активации среды для исполняемого файла python назначается другой путь, а в активной среде переменная среды $ PATH немного изменяется.

Обратите внимание на разницу между значениями $ PATH до и после активации:

$ echo $PATH
/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:

$ source env/bin/activate(env) 
$ echo $PATH
/Users/michaelherman/python-virtual-environments/env/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:

В последнем примере каталог bin нашей виртуальной среды теперь находится в самом начале, и это означает, что это первый каталог, где выполняется поиск при запуске исполняемого файла в командной строке. Таким образом, оболочка использует экземпляр Python нашей виртуальной среды вместо общесистемной версии.

Примечание:

Другие пакеты, в которые входит Python, например, Anaconda также МОГУТ манипулировать вашими настройками PATH при активировании. Просто знайте об этом на всякий случай, если возникнут проблемы с другими средами. Это может стать проблемой, если активировать несколько сред одновременно.

Возникают следующие вопросы:

  • В чём разница между исполняемыми файлами в различных средах?
  • Как исполняемый файл Python в виртуальной среде может использовать что-то кроме системных site‑packages?

Это можно объяснить тем, как Python запускается и где он находится в системе. На самом деле нет никакой разницы между этими двумя исполняемыми файлами Python. Важное значение имеют их каталоги.

Когда Python запускается, он ищет путь своего двоичного файла. В виртуальной среде это на самом деле просто копия или символическая ссылка на двоичный файл Python вашей системы. Затем он устанавливает местоположение sys.prefix и sys.exec_prefix на основе этого расположения, пропуская часть пути bin пути.

Путь, расположенный в sys.prefix, затем используется для поиска каталога site‑packages путем поиска относительного пути lib/pythonX.X/site‑packages/, где XX — это версия Python, которую вы используете.

В нашем примере двоичный файл находится по адресу /Users/michaelherman/python-virtual-environment/env/bin, что означает, что sys.prefix будет /Users/michaelherman/python-virtual-environment/env и, следовательно, используемый каталог site‑packages будет /Users/michaelherman/python-virtual-environment/env/lib/pythonX.X/site‑packages. Наконец, этот путь хранится в массиве sys.path
, который содержит все места, где может находиться пакет.

Управление виртуальными средами с помощью virtualenvwrapper    ↑

Хотя виртуальные среды, безусловно, решают некоторые большие проблемы управления пакетами, они не идеальны. После создания нескольких сред вы начнете понимать, что они сами создают собственные проблемы, большинство из которых вращаются вокруг управления самими средами. Для того, что бы помочь с этим справиться был создан инструмент virtualenvwrapper, который в свою очередь, представлет собой всего лишь несколько скриптов-оберток вокруг основного инструмента virtualenv.

Вот некоторые из более полезных функций virtualenvwrapper:

  • Упорядочивает все ваши виртуальные среды в одном месте;
  • Предоставляет методы, которые помогут легко создавать, удалять и копировать среды;
  • Предоставляет одну команду для переключения между средами.

Хотя некоторые из этих функций могут показаться небольшими или незначительными, но скоро вы узнаете, насколько они важны в вашем рабочим процессе.

Для начала надо скачать оболочку, используя pip:

$ pip install virtualenvwrapper

Примечание:

Для установки в Windows рекомендуется использовать virtualenvwrapper-win.

Как только он будет установлен, нужно будет активировать его функции оболочки. Это можно сделать, запустив source в установленном скрипте virtualenvwrapper.sh. При первой установке с помощью pip будет сообщение о точном местоположении virtualenvwrapper.sh. Или просто можно запустить следующее:

$ which virtualenvwrapper.sh
/usr/local/bin/virtualenvwrapper.sh

Используя этот путь, добавьте следующие три строки в файл запуска вашей оболочки. Если вы используете оболочку Bash, то поместите эти строки либо в файл ~/.bashrc, либо в файл ~/.profile. Для других оболочек, таких как zsh, csh или fish, вам потребуется использовать файлы запуска, специфичные для этих оболочек. Все, что имеет значение, это то, что эти команды выполняются при входе в систему или открытии новой оболочки:

export WORKON_HOME=$HOME/.virtualenvs  # Optional
export PROJECT_HOME=$HOME/projects     # Optional
source/usr/local/bin/virtualenvwrapper.sh

Прримечание:

Не требуется определять переменные окружения WORKON_HOME и PROJECT_HOME. У virtualenvwrapper уже есть значения по умолчанию для них, но их можно переопределить, задав новые значения.

Наконец, перезагрузите файл запуска:

$ source ~/.bashrc

Теперь в каталоге $WORKON_HOME должен быть каталог, содержащий все данные/файлы virtualenvwrapper:


$ echo $WORKON_HOME
/Users/michaelherman/.virtualenvs

Теперь команды оболочки помогут управлять средами. Вот лишь самые важные из них:

  • workon — список или изменение рабочей виртуальной среды;
  • deactivate — смена виртуальной среды на системную версию Python;
  • mkvirtualenv — создание новой вируальной средыв WORKON_HOME;
  • cdvirtualenv — сменить текущий рабочий каталог на $VIRTUAL_ENV;
  • rmvirtualenv — удалить виртуальную среду из WORKON_HOME.

Более подробная информация о командах, установке и конфигурировании virtualenvwrapper содержится в документации.

Теперь, в любое время, когда захотите начать новый проект, просто нужно сделать так:

$ mkvirtualenv my-new-project
(my-new-project) $

Таким образом, будет создана и активирована новая среда в каталоге, расположенном в $WORKON_HOME, где хранятся все среды virtualenvwrapper.

Чтобы прекратить использование этой среды, вам просто нужно отключить ее, как раньше:

(my-new-project) $ deactivate
$

Если у вас есть много сред для выбора, вы можете увидеть их все с помощью функции workon :

$ workon
my-new-project
my-django-project
web-scraper

Наконец, здесь же можно активировать нужную:

$ workon web-scraper
(web-scraper) $

Если вы хотите использовать один инструмент и переключаться между версиями Python, virtualenv позволит сделать именно это. Параметр -p virtualenv, позволяет вместе с командой which легко выбрать нужную версия Python. Например, мы хотим сделать Python 3 своей предпочтительной версией:

$ virtualenv -p 
$(which python3) blog_virtualenv

Этим мы создадим новую среду Python 3.

Как это работает? Команда which используется для поиска данной команды в переменной $PATH и возвращает полный путь к этой команде. Итак, полный путь к python3 был возвращен параметру -p, который принимает PYTHON_EXE. Это также может быть использовано для python2. Просто замените python3 на python2 (или python, если в вашей системе по умолчанию установлено python2).

Теперь вам не нужно помнить, где вы установили свою среду. Вы можете легко удалить или скопировать их по своему усмотрению, и каталог вашего проекта будет менее загроможден!

Использование различных версий Python    ↑

В отличие от старого инструмента virtualenv, pyvenv не поддерживает создание сред с произвольными версиями Python, что означает, что вы застряли, используя установку Python по умолчанию для всех создаваемых сред. Хотя вы можете обновить среду до последней версии системы Python (с помощью опции --upgrade), если она изменится, вы все равно не сможете указать конкретную версию.

Существует довольно много способов установки Python, но немногие из них достаточно просты или достаточно гибки, чтобы часто удалять и повторно устанавливать различные версии двоичного файла.

Это где за <цель="_blank" класс="ВН-ссылку" href="https://github.com/yyuu/pyenv в" rel="noreferrer noopener">pyenv и приходит, чтобы играть.

Несмотря на сходство имен (pyvenv vs pyenv), pyenv отличается тем, что позволяет переключаться между версиями Python как на системном уровне, так и на уровне проекта. Для pyvenv главное — отдельные модули, главным для pyenv является отдельной версии Python.

Вы можете начать с установки pyenv либо с Homebrew (на OS X) или pyenv-installer :

Homebrew

$ brew install pyenv

pyenv-installer

$ curl -L https://raw.githubusercontent.com/yyuu/pyenv-installer/master/bin/pyenv-installer | bash

Примечание:
К сожалению, pyenv не поддерживается Windows. Однако, есть несколько альтернатив pywin и anyenv.

В вашей системе уже установлен pyenv, вот несколько основных команд, которые вам, вероятно, будут интересны:

$ pyenv install 3.5.0  # Install new version
$ pyenv versions       # List installed versions
$ pyenv exec python -V # Execute 'python -V' using pyenv version

В этих нескольких строках мы устанавливаем версию Python 3.5.0, просим pyenv показать нам все доступные нам версии, а затем выполняем команду python -V используя версию, указанную pyenv.

Возможен полный контроль, при этом можно использовать любую из доступных версий для «глобального» или «локального» использования. Использование pyenv с командой local устанавливает версию Python для конкретного проекта или каталога путем сохранения номера версии в локальном файле .python-version. «Локальную» версию можно установить так:

$ pyenv local 2.7.11

Здесь в текущем каталоге создаётся файл .python-version:

$ ls -la
total 16
drwxr-xr-x  4 michaelherman  staff  136 Feb 22 10:57 .
drwxr-xr-x  9 michaelherman  staff  306 Jan 27 20:55 ..
-rw-r--r--  1 michaelherman  staff    7 Feb 22 10:57 .python-version
-rw-r--r--  1 michaelherman  staff   52 Jan 28 17:20 main.py

Этот файл содержит только значение «2.7.11». Теперь, когда вы выполняете скрипт с использованием pyenv, он загружает этот файл и использует указанную версию, предполагая, что она действителено существует в вашей системе.

Теперь перейдем к нашему примеру. Допустим, у нас есть простой скрипт main.py в каталоге нашего проекта, который выглядит следующим образом:

import sys
print('Using version:', sys.version[:5])

Все, что он делает, это распечатывает номер версии используемого исполняемого файла Python. Используя pyenv и команду exec, мы можем запустить этот скрипт с любой из установленных версий Python:

$ python main.py
Using version: 2.7.5
$ pyenv global 3.5.0
$ pyenv exec python main.py
Using version: 3.5.0
$ pyenv local 2.7.11
$ pyenv exec python main.py
Using version: 2.7.11

Обратите внимание, как pyenv exec python main.py использует нашу «глобальную» версию Python по умолчанию, но затем она использует «локальную» версию после того, как она установлена для текущего каталога.

Это может быть очень полезно для разработчиков, у которых много проектов с различными требованиями к версии. Вы можете не только легко изменить версию по умолчанию для всех проектов (через global), но в особых случаях её можно переопределить

Заключение    ↑

В этой статье вы узнали не только о том, как хранятся и разрешаются зависимости Python, но и о том, как вы можете использовать различные инструменты сообщества для решения различных проблем с упаковкой и версиями.

Как вы можете видеть, благодаря огромному сообществу Python в вашем распоряжении немало инструментов для решения этих распространенных проблем. По мере развития в качестве разработчика обязательно уделите время тому, чтобы научиться использовать эти инструменты в своих интересах. Вы можете даже найти непреднамеренное их использование или научиться применять аналогичные концепции к другим языкам, которые вы используете.

Оригинал (англ.): Python Virtual Environments: A Primer

Опубликовано Вадим В. Костерин

ст. преп. кафедры ЦЭиИТ. Автор более 130 научных и учебно-методических работ. Лауреат ВДНХ (серебряная медаль).

Оставьте комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *