В данной статье мы рассмотрим, как использовать виртуальную среду для создания и управлять ими отдельно в ваших проектах Python, используя разные версии Python для выполнения, а также рассмотрим, как хранятся и разрешаются зависимости Python.
Зачем нужна виртуальная среда?
Python, как и большая часть других современных языков программирования, имеет собственный, уникальный способ загрузки, хранения и разрешения пакетов (или модулей). Это имеет свои преимущества, однако были принятые некоторые интересные решения, на счет хранения и разрешения пакетов, которые привели к определенным проблемам, а именно: как и где эти пакеты хранятся?
Содержание
- Зачем нужна виртуальная среда?
- Что такое виртуальная среда?
- Использование виртуальной среды
- Как работает виртуальная среда?
- Управление виртуальной средой при помощи virtualenvwrapper
- Использование разных версий Python
- Вывод
Существует несколько разных расположений, в которых хранятся пакеты, которые можно установить в вашей системе. Например, большая часть системных пакетов хранятся в дочернем каталоге пути, который, в свою очередь, хранится в sys.prefix.
На Mac OS X, вы можете легко найти, где именно sys.prefix указывает на использование оболочки Python:
Pythonimport sysprint(sys.prefix) # ‘/System/Library/Frameworks/Python.framework/Versions/3.5’12import sysprint(sys.prefix) # ‘/System/Library/Frameworks/Python.framework/Versions/3.5’
К нашей статье в большей мере относятся сторонние пакеты, установленные при помощи easy_install или pip, обычно располагаются в одном из каталогов, на которую указывает site.getsitepackages:
Pythonimport sitedata = site.getsitepackages()print(data)1234import sitedata = site.getsitepackages() print(data)
Результат:
Python[ ‘/System/Library/Frameworks/Python.framework/Versions/3.5/Extras/lib/python’, ‘/Library/Python/3.5/site-packages’]1234[ ‘/System/Library/Frameworks/Python.framework/Versions/3.5/Extras/lib/python’, ‘/Library/Python/3.5/site-packages’]
Зачем нам все эти детали?
Очень важно иметь представление об этом, так как по умолчанию, каждый объект вашей системы будет использовать одинаковые каталоги для хранения и разрешения пакетов (сторонних библиотек. На первый взгляд это не выглядит чем-то значительным. Это так, но только в отношении системных пакетов, являющихся частью стандартной библиотеки Python – но сторонние пакеты – это другое дело.
Представим следующий сценарий, где у вас есть два проекта: проект А и проект Б, которые оба имеют зависимость от одной и той же библиотеки – проект В. Проблема становится явной, когда мы начинаем запрашивать разные версии проекта В. Может быть так, что проект А запрашивает версию 1.0.0, в то время как проект Б запрашивает более новую версию 2.0.0, к примеру.
Это большая проблема Python, поскольку он не может различать версии в каталоге «site-packages». Так что обе версии 1.0.0 и 2.0.0 будут находиться с тем же именем в одном каталоге:
Shell/System/Library/Frameworks/Python.framework/Versions/3.5/Extras/lib/python/ProjectC1/System/Library/Frameworks/Python.framework/Versions/3.5/Extras/lib/python/ProjectC
И так как проекты хранятся в соответствии с их названиями, то нет различий между версиями. Таким образом, проекты А и Б должны будут использовать одну и ту же версию, что во многих случаях неприемлемо.
Тут-то и вступает в игру виртуальная среда (вместе с инструментами virtualenv/ven)
Что такое виртуальная среда?
В корне своем, главная задача виртуальной среды Python – создание изолированной среды для проектов Python.
Это значит, что:
Каждый проект может иметь свои собственные зависимости, вне зависимости от того, какие зависимости у другого проекта.
И так, в нашем небольшом примере вверху, нам просто нужно создать раздельную виртуальную среду для проектов А и Б. Каждая среда, в свою очередь, сможет зависеть от любой версии проекта В, независимо друг от друга.
Это хорошо тем, что у нас нет ограничений на то, в скольких экземплярах будет наша виртуальная среда, так как они являются обычными каталогами, в которых содержится несколько скриптов. Плюс, их очень легко создать при помощи инструментов командной строки virtualenv или pyenv.
Использование виртуальной среды
Перед тем, как начать: если вы не пользуетесь Python 3, вам нужно будет установить инструмент virtualenv при помощи pip:
Shell$ pip install virtualenv1$ pip install virtualenv
Если вы используете Python 3, у вас уже должен быть модуль venv, установленный в стандартной библиотеке.
Предположим, что вы пользуетесь последней версией инструмента venv, так как между ним и virtualenv существует несколько различий в отношении команд. По большому счету, это два весьма разных инструмента.
Начнем с создания нового каталога, с которым мы будем работать:
Shellmkdir python-virtual-environments && cd python-virtual-environments1mkdir python-virtual-environments && cd python-virtual-environments
Создание новой виртуальной среды внутри каталога:
Shell# Python 2:$ virtualenv env# Python 3$ python3 -m venv env12345# 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», структура каталога которого схожа со следующей:
Shell├── 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.cfg1234567891011121314151617├── 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 – С-заголовки, компилирующие пакеты Python;
- lib – копия версии Python вместе с папкой «site-packages», в которой установлена каждая зависимость.
Далее, у нас есть копии или символические ссылки нескольких различных инструментов Python. Эти файлы используются для обеспечения того, чтобы команды и код Python выполнялись в контексте нынешней среды, таким образом, достигается изоляция от глобальной среды. Мы рассмотрим это детальнее в следующем разделе.
Более интересные сейчас – скрипты activate в папке bin. Эти скрипты используются для настройки вашей оболочки для использования исполняемого файла среды Python и его сайтовых пакетов по умолчанию.
Чтобы использовать эти пакеты (или ресурсы) среды в изоляции, вам нужно «активировать» их. Чтобы сделать это, просто запустите:
Shellsource env/bin/activate1source env/bin/activate
Обратите внимание на то, что ваше приглашение командной строки теперь носит префикс вашей среды (в нашем случае – env). Это индикатор того, что env в данный момент активен, что в свою очередь говорит о том, что выполнимые файлы Python используют пакеты и настройки только этой среды.
Чтобы показать изолированный пакет в действии, мы можем использовать модуль bcrypt в качестве примера. Скажем, что модуль bcrypt установлен где-нибудь в системе, но не в нашей виртуальной среде.
Перед тем как проверить это, нам нужно вернуться назад в контекст «system» , выполнив команду deactivate:
Shell(env) $ deactivate1(env) $ deactivate
Теперь ваш сеанс оболочки вернулся в норму, а команда python ссылается на общую установку Python. Помните: это можно делать когда угодно, после закрытия определенной виртуальной среды.
Теперь установим bcrypt и используем его для хеширования пароля:
Shell$ pip -q install bcrypt$ python -c «import bcrypt; print(bcrypt.hashpw(‘password’.encode(‘utf-8’), bcrypt.gensalt()))»$2b$12$vWa/VSvxxyQ9d.WGgVTdrell515Ctux36LCga8nM5QTW0.4w8TXXi123$ pip -q install bcrypt$ python -c «import bcrypt; print(bcrypt.hashpw(‘password’.encode(‘utf-8’), bcrypt.gensalt()))»$2b$12$vWa/VSvxxyQ9d.WGgVTdrell515Ctux36LCga8nM5QTW0.4w8TXXi
Что произойдет, если мы попробуем ту же команду, когда виртуальная среда активна?
Shell$ source env/bin/activate(env) $ python -c «import bcrypt; print(bcrypt.hashpw(‘password’.encode(‘utf-8’), bcrypt.gensalt()))»Traceback (most recent call last): File «<string>», line 1, in <module>ImportError: No module named ‘bcrypt’1234567$ source env/bin/activate (env) $ python -c «import bcrypt; print(bcrypt.hashpw(‘password’.encode(‘utf-8’), bcrypt.gensalt()))» Traceback (most recent call last): File «<string>», line 1, in <module>ImportError: No module named ‘bcrypt’
Как мы видим, поведение команды the python -c «import bcrypt…» меняется после вызова источника env/bin/activate.
В одном примере, у нас есть доступный нам bcrypt, а в другом его нет. Это тот тип разделения, который мы ищем для виртуальной среды, и мы к нему пришли.
Как работает виртуальная среда?
Что именно имеется ввиду под «активировать» среду? Понимание того, что именно происходит под капотом, может быть очень важно для разработчика, особенно когда вам нужно понять выполнение виртуальной среды, разрешение зависимостей, и так далее.
Чтобы объяснить, как это работает, для начала проверим расположения разных исполняемых файлов python. С «деактивированной» средой запускаем:
Shell$ which python/usr/bin/python12$ which python/usr/bin/python
Теперь активируем и снова запустим команду:
Python$ source env/bin/activate(env) $ which python/Users/michaelherman/python-virtual-environments/env/bin/python123$ source env/bin/activate(env) $ which python/Users/michaelherman/python-virtual-environments/env/bin/python
Активировав среду, мы теперь получаем другой путь к исполнимому файлу python, так как в активной среде, переменная среды $PATH несколько отличается.
Обратите внимание на разницу между первым путем в $PATH до и после активации:
Python$ 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:123456$ 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, также могут выполнять манипуляции с вашим путем, если вы активируете их. Просто имейте это ввиду на случай, если вы столкнетесь с проблемами, связанными с другими виртуальными средами. Проблема может возникнуть при активации нескольких сред одновременно.
Это наталкивает на вопросы:
- В чем разница между этими исполняемыми файлами?
- Каким образом виртуальная среда исполняемого файлаPython может использовать что-либо, кроме системных сайт-пакетов?
Это можно объяснить тем, как Python запускается и где он расположен в системе. Нет разницы между двумя исполняемыми файлами Python. Суть заключается в расположении каталога
Когда Python запускается, он ищет путь своего двоичного файла (в виртуальной среде он является копией или символической ссылке системного бинарного файла Python). Далее, он устанавливает расположение sys.prefix и sys.exec_prefix согласно с этим расположением, опуская часть bin в пути.
Путь, находящийся в sys.prefix далее используется для поиска каталога site-packages, путем поиска по связанного с ним пути lib/pythonX.X/site-packages/, где Х.Х – это версия используемого вами Python.
В нашем примере, бинарный файл расположен в /Users/michaelherman/python-virtual-environments/env/bin, это значит, что sys.prefix может быть /Users/michaelherman/python-virtual-environments/env, следовательно, используемый каталог site-packages может быть /Users/michaelherman/python-virtual-environments/env/lib/pythonX.X/site-packages. Наконец, этот путь наложен в массиве sys.path, который содержит все расположения, которые пакет может использовать.
Управление виртуальной средой при помощи virtualenvwrapper
Несмотря на то, что виртуальная среда определенно решает ряд проблем с управлением пакетами, она не идеальна. После создания нескольких виртуальных сред, вы обнаружите, что они создают некоторые проблемы сами по себе, большая часть которых вращается вокруг управления самими виртуальными средами. Чтобы помочь с этим, был создан инструмент virtualenvwrapper, который представляет собой набор оберточных скриптов вокруг основного инструмента virtualenv.
Самые полезные функции virtualenvwrapper:
- Организация каждой виртуальной среды в одном расположении;
- Предоставляются методы, которые помогут вам легко создавать, удалять и копировать виртуальную среду, а также,
- Предоставляет одну команду для переключения между средами
Некоторые функции могут показаться узкими, или незначительными, вы быстро поймете, что они – это отличные инструменты для вашего рабочего ритма.
Перед началом, вы можете скачать обёртку при помощи pip:
Shell$ pip install virtualenvwrapper1$ pip install virtualenvwrapper
Для Windows нужно использовать virtualenvwrapper-win
После завершения установки, нам нужно активировать его функции оболочки. Это можно сделать, запустив источник установленного скрипта virtualenvwrapper.sh. Кода вы в первый раз устанавливаете его при помощи pip, выдача установки укажет вам точное расположение virtualenvwrapper.sh. Впрочем, вы можете просто запустить команду:
Shell$ which virtualenvwrapper.sh/usr/local/bin/virtualenvwrapper.sh12$ which virtualenvwrapper.sh/usr/local/bin/virtualenvwrapper.sh
Используя данный путь, добавьте следующие три строки в стартовый файл вшей оболочки. Если оболочку Bash, вы можете разместить эти строки и в файле ~/.bashrc file or ~/.profile. Для других оболочек, таких как zsh, csh или fish, вам может понадобиться определенные файлы запуска для этой оболочки. Главное, чтобы эти команды выполнялись при открытии новой оболочки или входе в неё.
Shellexport WORKON_HOME=$HOME/.virtualenvs # optionalexport PROJECT_HOME=$HOME/projects # optionalsource /usr/local/bin/virtualenvwrapper.sh123export WORKON_HOME=$HOME/.virtualenvs # optionalexport PROJECT_HOME=$HOME/projects # optionalsource /usr/local/bin/virtualenvwrapper.sh
От нас не требуется определять переменные виртуальной среды WORKON_HOME и PROJECT_HOME. В virtualenvwrapper имеются установленные по умолчанию переменные для них, но вы можете перезаписать их, указав значения.
Наконец, перезагружаем файл запуска:
Shell$ source ~/.bashrc1$ source ~/.bashrc
Теперь здесь должен быть каталог, расположенный в $WORKON_HOME, который содержит все данные и файлы virtualenvwrapper:
Shell$ echo $WORKON_HOME/Users/michaelherman/.virtualenvs12$ echo $WORKON_HOME/Users/michaelherman/.virtualenvs
Кроме этого, у вас теперь в распоряжении имеются доступные команды оболочки, которые помогут в управлении виртуальной средой. Вот несколько из них:
- workon
- deactivate
- mkvirtualenv
- cdvirtualenv
- rmvirtualenv
Для дополнительной информации о командах, установке и настройке virtualenvwrapper, вы можете ознакомиться с их документацией.
Теперь, когда бы вы не начинали новый проект, все что вам нужно, это:
Shell$ mkvirtualenv my-new-project(my-new-project) $12$ mkvirtualenv my-new-project(my-new-project) $
Это создаст и активирует новую виртуальную среду в каталоге, расположенном в $WORKON_HOME, где хранятся все среды virtualenvwrapper.
Чтобы прекратить использование этой среды, вам всего лишь нужно её деактивировать, как мы делали это раньше:
Shell(my-new-project) $ deactivate$12(my-new-project) $ deactivate$
Если у вас есть широкий выбор виртуальных сред, вы можете отсортировать их по списку при помощи функции workon:
Shell$ workonmy-new-projectmy-django-projectweb-scraper1234$ workonmy-new-projectmy-django-projectweb-scraper
И, наконец, активировать:
Python$ workon web-scraper(web-scraper) $12$ workon web-scraper(web-scraper) $
Если вы хотите иметь один инструмент и переключаться между версиями Python, virtualenv позволит вам это сделать. Virtualenv содержит параметр -р, который позволяет вам выбрать, какую версию Python использовать. Совместите это с командой which, и мы можем быстро выбрать предпочитаемую версию Python. К примеру, скажем, что мы хотим выбрать Python 3 в качестве нашей основной версии:
Shell$ virtualenv -p $(which python3) blog_virtualenv1$ virtualenv -p $(which python3) blog_virtualenv
Это создаст новую среду python3.
Так как же это работает? Команда which используется для поиска переданной команды в вашей переменной $PATH и возвращает полный путь к этой команде. Так, полный путь к Python3 вернулся параметру -р , который в свою очередь принимает PYTHON_EXE. Это также можно практиковать и в Python2. Просто замените python3 на python2 (или python, если вы используете python2 по умолчанию).
Теперь вам не нужно помнить где вы установили вашу виртуальную среду. Вы можете просто удалить или копировать ее как хотите, разгрузив ваш проектный каталог.
Использование разных версий Python
В отличие от старого virtualenv, pyvenv не поддерживает создание виртуальной среды в произвольных версиях Python. Это значит, что вам придется использовать установленный Python 3 по умолчанию для каждой создаваемой вами виртуальной среды. Хотя вы можете обновить среду до последней системной версии Python (через опцию –upgrade) если она поменялась, вы все еще не можете указывать конкретную версию.
Существует предостаточно способов установить Python, но только некоторые из них достаточно простые или гибкие, чтобы повторно удалять и переустанавливать разные бинарные версии файлов.
Здесь и вступает в игру pyenv.
Несмотря на схожесть в названиях (pyvenv и pyenv), pyenv отличается тем, что он направлен на то, чтобы помочь переключаться между версиями Python на как на системном уровне, так и на проектном. Другими словами, задача pyvenv разделять модули, задача pyenv – разделять версии Python.
Вы можете начать с установки pyenv как при помощи Homebrew (на OS X), или при помощи проекта pyenv-installer:
Homebrew
Shell$ brew install pyenv1$ brew install pyenv
pyenv-installer
Shell$ curl -L https://raw.githubusercontent.com/yyuu/pyenv-installer/master/bin/pyenv-installer | bash1$ curl -L https://raw.githubusercontent.com/yyuu/pyenv-installer/master/bin/pyenv-installer | bash
К сожалению, pyenv не поддерживается Windows. Вы можете воспользоваться альтернативами в виде pywin и anyenv.
После установки pyenv в вашей системе, есть несколько базовых команд, которые вас могут заинтересовать:
КОД # Install new version установка новой версии
КОД # Внесение установленных версий в список
КОД # Выполнение «python-V» с использованием версии pyenv
Shell$ pyenv install 3.5.0 # Установка новой версии$ pyenv versions # Внесение установленных версий в список$ pyenv exec python -V # Выполнение «python-V» с использованием версии pyenv123$ pyenv install 3.5.0 # Установка новой версии$ pyenv versions # Внесение установленных версий в список$ pyenv exec python -V # Выполнение «python-V» с использованием версии pyenv
Этими тремя строками мы устанавливаем версию Python 3.5.0, просим pyenv показать все доступные нам версии, после чего выполнить команду python –V, используя определенную pyenv версию.
Чтобы дать вам больше контроля, вы можете использовать любую доступную версию как для «глобального», так и «локального». Использование pyenv с локальными командами настраивает версию Python на определенный проект или директорию, сортируя версию в локальном файле .python-version. Мы можем настроить «локальную» версию следующим образом:
Shell$ pyenv local 2.7.111$ pyenv local 2.7.11
Это создает файл .python-version в нашем текущем каталоге, как вы можете видеть здесь:
Shell$ ls -latotal 16drwxr-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.py123456$ ls -latotal 16drwxr-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 в нашем проектном каталоге, который выглядит следующим образом:
Pythonimport sysprint(‘Using version:’, sys.version[:5])12import sysprint(‘Using version:’, sys.version[:5])
Все что он делает, это выводит номер версии используемого выполняемого файла Python. При помощи pyenv и команды exec, мы можем запустить скрипт с любой другой установленной версией Python.
Shell$ python main.pyUsing version: 2.7.5$ pyenv global 3.5.0$ pyenv exec python main.pyUsing version: 3.5.0$ pyenv local 2.7.11$ pyenv exec python main.pyUsing version: 2.7.1112345678910$ python main.pyUsing version: 2.7.5 $ pyenv global 3.5.0$ pyenv exec python main.pyUsing version: 3.5.0 $ pyenv local 2.7.11$ pyenv exec python main.pyUsing version: 2.7.11
Обратите внимание на то, как pyenv exec python main.py использует нашу «глобальную» версию Python по умолчанию, но затем он использует «локальную» версию после ее установки в текущий каталог.
Это может быть мощным орудием для разработчиков, работающих со множеством проектов с различными требованиями к версии. Вы можете не только изменить версию по умолчанию для всех проектов (через global), но также переопределять ее для указания особых случаев.
Вывод
В данной статье вы узнали больше о том, как хранятся и разрешаются зависимости Python, как использовать различные инструменты для помощи в обходе различных проблем, связанных с пакетами и версиями.
Как вы видите, благодаря огромному сообществу Python, в вашем распоряжении имеется обширное количество инструментов для помощи с решением этих проблем. С вашим ростом в качестве разработчика, убедитесь, что вы уделили время тому, как использовать эти инструменты в своих интересах. Вы даже можете найти особенное использование для них, или применять схожие концепции в других языках программирования, которые вы используете.