使用 pyenv 在 macOS 上创建多版本且能隔离的 Python 环境(本文部分内容已过时)

和众多 Linux 分发版本一样,macOS 中也自带了一份 Python 运行环境。打开命令行,直接键入 python 即可,触手可及。

但是,系统中自带的 Python 版本一般是 Python 2.7。如果希望尝试其他版本,这份系统自带的 Python 就无法满足需求了。很多人下意识的做法是去官方网站,寻求一份需要的版本进行安装,这种方式虽然正统,但也存在一定的弊端:不够灵活、会在系统中安装额外的软件和工具、切换不同 Python 版本时相对比较麻烦。

今天要介绍的 pyenv 正是为了解决这些问题而出现一款工具。pyenv 是一款 Python 版本管理器,可以让用户轻松的在多个 Python 版本之间进行切换,此外,pyenv 还可以集成 virtualenv 以项目为单位进行环境隔离。经由 pyenv 管理的 Python 环境(或者是项目)还可以继承给 Atom 或者 PyCharm,这样一来,开发人员只要打开了某个项目,也就打开了专门为这个项目创建的独立环境。

接下来我们将演示如何在 macOS 下配置 pyenv 环境。由于下面的步骤严重依赖国外网站,所以请确保命令行下配置了使用 http_proxy 和 https_proxy 环境变量的科学上网,否则可能导致安装失败。

安装

pyenv-installer 是 pyenv 附带的一份安装脚本。用户仅需一条命令,即可调用 pyenv-installer 脚本完成安装。

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

这个脚本不仅会帮我们安装 pyenv,还会附带安装一些 pyenv 的插件,其中就包括 virtualenv。因此,在跑完这个脚本之后,virtualenv 也已经可以使用了。

我们还需要在 .bash_profile 中添加以下两行,使得每次打开命令行之后,pyenv 都可以自动配置在环境变量中。

# Enable pyenv
eval "$(pyenv init -)"
eval "$(pyenv virtualenv-init -)"

添加之后,保存 .bash_profile,再执行 source,即可生效。

$ source ~/.bash_profile

卸载

pyenv 会安装在用户家目录下的 .pyenv 文件夹中,不会安装在家目录外的系统文件夹中。因此,只要删除该文件夹,即是删除了 pyenv。

$ rm -rf ~/.pyenv

Python 版本管理

在 pyenv 生效后(source或新开终端),便可以使用 pyenv 命令行工具进行 Python 版本管理。

查看所有可下载的 Python 版本
$ pyenv install --list
Available versions:
  2.1.3
  2.2.3
  2.3.7
  2.4
  ...
  stackless-3.3-dev
  stackless-3.3.5
  stackless-3.4.1
  stackless-3.4.2
安装某个 Python 版本
$ pyenv install 3.5.1
Downloading Python-3.5.1.tar.xz...-> https://www.python.org/ftp/python/3.5.1/Python-3.5.1.tar.xz
Installing Python-3.5.1...
Installed Python-3.5.1 to /Users/colinleefish/.pyenv/versions/3.5.1

这里的操作实际是从官方下载源码,然后现场编译出 Python 环境并放在 ~/.pyenv 中。注意:如果是首次尝试安装,多数都会因为各种原因失败。我故意没写解决办法,请自行上网寻求方法。[滑稽]

另外,经测试,在网络状况较好的环境中,下载该源码包的速度很理想。如果使用 http_proxy 等科学上网,反而会出现验证 HTTPS 超时的可能。因此,如果在网速快的情况下进行下载,建议暂时取消科学上网。

查看已安装的 Python 版本和已创建的环境
$ pyenv versions
  system
  2.7.13
  2.7.13/envs/mkdocs
* 2.7.13/envs/tango_with_django
  ...
  tango_with_django
  theotherbarn

system 为系统自带的 Python 环境;标星号的为当前激活的全局 Python 环境。

基于某个 Python 版本创建环境隔离的项目
$ pyenv virtualenv 3.4.6 my-awesome-project
Using base prefix '/Users/colinleefish/.pyenv/versions/3.4.6'
New python executable in /Users/colinleefish/.pyenv/versions/3.4.6/envs/my-awesome-project/bin/python3.4
Also creating executable in /Users/colinleefish/.pyenv/versions/3.4.6/envs/my-awesome-project/bin/python
Installing setuptools, pip, wheel...done.

在创建该环境的过程中,virtualenv 会很贴心地帮我们安装好 setuptools, pip 和 wheel,这样一来,我们马上就可以使用 pip 了。

激活某个项目
$ pyenv activate my-awesome-project
pyenv-virtualenv: prompt changing will be removed from future release. configure `export PYENV_VIRTUALENV_DISABLE_PROMPT=1' to simulate the behavior.
(my-awesome-project)$

激活时,在上面实例第二行会有一个提醒,可以放心忽略。激活后,在命令行的开头部分会有括号标注的项目名称。

使用该项目
(my-awesome-project)$ python --version
Python 3.4.6
(my-awesome-project)$ pip install requests
Collecting requests
  Using cached requests-2.18.4-py2.py3-none-any.whl
Collecting chardet<3.1.0,>=3.0.2 (from requests)
  Using cached chardet-3.0.4-py2.py3-none-any.whl
Collecting idna<2.7,>=2.5 (from requests)
  Using cached idna-2.6-py2.py3-none-any.whl
Collecting certifi>=2017.4.17 (from requests)
  Using cached certifi-2017.7.27.1-py2.py3-none-any.whl
Collecting urllib3<1.23,>=1.21.1 (from requests)
  Using cached urllib3-1.22-py2.py3-none-any.whl
Installing collected packages: chardet, idna, certifi, urllib3, requests
Successfully installed certifi-2017.7.27.1 chardet-3.0.4 idna-2.6 requests-2.18.4 urllib3-1.22
(my-awesome-project)$

我们在这个隔离的环境中安装了 requests,这个过程中还安装了一些 requests 的依赖包。那它们都被安装在了哪里呢?

(my-awesome-project)$ cd ~/.pyenv/versions/my-awesome-project/lib/python3.4/site-packages
(my-awesome-project)$ ls
__pycache__                   easy_install.py               pkg_resources                 urllib3
certifi                       idna                          requests                      urllib3-1.22.dist-info
certifi-2017.7.27.1.dist-info idna-2.6.dist-info            requests-2.18.4.dist-info     wheel
chardet                       pip                           setuptools                    wheel-0.30.0.dist-info
chardet-3.0.4.dist-info       pip-9.0.1.dist-info           setuptools-36.6.0.dist-info

这些依赖包,都被安装在了 ~/.pyenv 下一个独立的文件夹中,而且和系统的 Python 环境、其他 Python 环境做到了隔离。日后如果不再需要该项目,只需使用 pyenv 自带的命令删除,或删除这个项目文件夹即可。

如果您使用 Atom 等编辑器,并可以从命令行启动,这类编辑器会自动继承当前的项目环境,这样就可以在编辑器中运行该项目的代码了。

(my-awesome-project)$ atom
取消激活某个项目
(my-awesome-project)$ pyenv deactivate
$

使用 pyenv deactivate 即可取消激活当前的环境。在此之后,命令行提示符前面的括号内容就消失了,Python 环境回归了正常的全局环境。

设置全局 Python 环境
$ pyenv global my-awesome-project
(my-awesome-project)$ python --version
Python 3.4.6

使用 pyenv global 命令,可以为命令行设置全局生效的环境或项目。在关掉当前 Shell,再新开其他 Shell 时,一直都会使用当前环境。

如果希望恢复该设置,使用 pyenv global system。

(my-awesome-project)$ pyenv global system
$

此时,全局环境便又恢复为系统默认的环境了。

查看当前 Python 项目或环境
(my-awesome-project)$ pyenv version
my-awesome-project (set by /Users/colinleefish/.pyenv/version)

在 PyCharm 中使用某个特定的项目环境

PyCharm 也是以独立的项目来组织代码的。每个项目中,均可以设置一个已有的 Python 环境。只要指定这个项目的 Python 解释器(interpretor,其实就是 Python 主程序)即可。

打开任意环境,在菜单栏中通过 “Run” - “Edit Configurations” 即可引导至项目环境设置界面。


项目环境设置界面

在 “Python interpreter” 处,只要指定所需的 Python 环境,即是将整个环境,以及依赖包都应用在了这个 PyCharm 项目上。此时便可以进行开发了。

延伸阅读

pyenv 是受到 rbenv 启发而产生的项目,后者主要解决了 Ruby 环境下的多版本隔离问题。pyenv 使用了一种叫做 Shim 的命令行黑科技。技术细节在这里。更多文档,可以访问该项目的 Github Wiki

后记(2018-01-12)

在一次给朋友的 Mac 笔记本配置 pyenv 的过程中发现:当时使用 brew 下载的那个版本有点问题,始终无法安装新的 Python 版本。后来,删掉了 brew 的 pyenv,使用 pyenv 自带的安装工具(pyenv-installer)重新下载了之后,故障得以解决。

后记(2018-02-02)

今天在一台新电脑上安装 pyenv 时发现:使用 pyenv activate my_project 之后可能依然无法正确切换到预期的版本。具体的原因暂不清楚,但本文中介绍的方法可能已经有错误,或者不再有效,请读者在使用时一定参照官方文档来使用。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,980评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,178评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,868评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,498评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,492评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,521评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,910评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,569评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,793评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,559评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,639评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,342评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,931评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,904评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,144评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,833评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,350评论 2 342

推荐阅读更多精彩内容