这是一篇旧文,编写于2017年,用于公司内部交流。整理更新后于2019年04月06日重发,内容有效期乐观估计半年,阅读请注意保质期。

为什么用python虚拟环境

python版本差异

python当前主要有2个release版本 Python 2.7.16Python 3.7.3 ,这两个版本在一些语法上存在较大差异。

如果你从网上下载了一段python代码,却运行不起来,首先要排除的是python版本问题。比如下面这个 hello_python.py ,代码非常简单,就一句打印 hello,world 到屏幕上。

1
print "hello,world"

如果你使用python2.7,恭喜你可以很好的跑起来,如下:

1
2
(python27) ➜  python hello_python.py
hello,world

如果你使用的是python3,可能就实现从入门到放弃:(

1
2
3
4
5
(python37) ➜  python hello_python.py
  File "hello_python.py", line 3
    print "hello,world"
                      ^
SyntaxError: Missing parentheses in call to 'print'. Did you mean print("hello,world")?

python3 中让代码正常运行的办法和提示一样,修改语句为 print("hello,world")

python2.7已经 “过时”,pip运行是会提示:

1
DEPRECATION: Python 2.7 will reach the end of its life on January 1st, 2020. Please upgrade your Python as Python 2.7 won't be maintained after that date. A future version of pip will drop support for Python 2.7.

现实状况却是一些库的版本问题或者历史遗留问题,可能需要在python2和python3之间切换。

python使用场景差异

python语言应用非常广泛,涉及服务器脚本、爬虫、程序开发、科学计算,大数据,机器学习等。不同的场景下,使用的库是有差异:

使用场景 常用库
程序开发 flask/django
爬虫 requests/beautifulsoup4/scrapy
科学计算 pandas/numpy/matplotlib

库又会依赖另外的库,这样如果全部安装在一个环境里,难以规避库的版本冲突。

鉴于python版本差异和使用场景差异,推荐使用虚拟环境进行隔离管理,省事不少。

怎么使用虚拟环境

使用 pip

使用虚拟环境之前,我们先花一点点时间来了解python的包安装工具 pip , 相信我这很简单。

Python的最大的优势之一是丰富的库,跨平台,在UNIX,Windows和Macintosh兼容很好。

安装这些库,让开发速度飚起来,就需要使用 pip

下面使用pip安装requests库示例:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
(py27studio) ➜  pytest pip install requests
Looking in indexes: https://pypi.tuna.tsinghua.edu.cn/simple
Collecting requests
  Downloading https://pypi.tuna.tsinghua.edu.cn/packages/f1/ca/10332a30cb25b627192b4ea272c351bce3ca1091e541245cccbace6051d8/requests-2.20.0-py2.py3-none-any.whl (60kB)
    100% |████████████████████████████████| 61kB 1.5MB/s
Collecting chardet<3.1.0,>=3.0.2 (from requests)
  Using cached https://pypi.tuna.tsinghua.edu.cn/packages/bc/a9/01ffebfb562e4274b6487b4bb1ddec7ca55ec7510b22e4c51f14098443b8/chardet-3.0.4-py2.py3-none-any.whl
Collecting urllib3<1.25,>=1.21.1 (from requests)
  Downloading https://pypi.tuna.tsinghua.edu.cn/packages/62/00/ee1d7de624db8ba7090d1226aebefab96a2c71cd5cfa7629d6ad3f61b79e/urllib3-1.24.1-py2.py3-none-any.whl (118kB)
    100% |████████████████████████████████| 122kB 1.5MB/s
Collecting certifi>=2017.4.17 (from requests)
  Downloading https://pypi.tuna.tsinghua.edu.cn/packages/56/9d/1d02dd80bc4cd955f98980f28c5ee2200e1209292d5f9e9cc8d030d18655/certifi-2018.10.15-py2.py3-none-any.whl (146kB)
    100% |████████████████████████████████| 153kB 287kB/s
Collecting idna<2.8,>=2.5 (from requests)
  Downloading https://pypi.tuna.tsinghua.edu.cn/packages/4b/2a/0276479a4b3caeb8a8c1af2f8e4355746a97fab05a372e4a2c6a6b876165/idna-2.7-py2.py3-none-any.whl (58kB)
    100% |████████████████████████████████| 61kB 131kB/s
Installing collected packages: chardet, urllib3, certifi, idna, requests
Successfully installed certifi-2018.10.15 chardet-3.0.4 idna-2.7 requests-2.20.0 urllib3-1.24.1

从示例可见 pip 的2个特点:

  1. 快速安装。命令行中一键安装完成。

  2. 自动解决依赖。在安装requests的同时还安装了: chardet, urllib3, certifi, idna 并且自动解决各个库的版本问题, 一般情况下我们不用关心这些细节。

下面是 pip的一些常用命令

1
2
3
4
5
6
7
8
# 列出库列表
pip list
# 升级pip
pip install pip -U
# 安装指定的库
pip install name
# 删除指定的库 
pip uninstall name

了解 pip 的常用命令后,可以愉快的写代码了。逐渐你会遇到在不同机器上同步库或者同事使用你的代码,需要安装相同的库。这时候你就需要pip的2个进阶命令了。

1
2
3
4
# 将当期环境中的库列表形成 requirements.txt 文件
pip freeze >requirements.txt
# 根据 requirements.txt 批量安装库
pip install -r requirements.txt

你可以使用下面2个命令,获取pip的使用帮助,了解更多

1
2
pip help
pip install -h

由于PyPI服务位于国外,访问起来比较缓慢,可以使用国内的一些源进行加速

1
2
设置pip使用国内源
pip config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple

一些其它的源: 豆瓣源:http://pypi.douban.com/simple/ 阿里云源: https://mirrors.aliyun.com/pypi/simple/

其它平台/语言也有类似的解决方案,如果你有兴趣可以使用下面关键字自行了解。

yum/apt/npm/brew/maven…

使用 venv

Python 从3.3 版本开始,自带了一个虚拟环境 venv,在 PEP-405 中可以看到它的详细介绍。

在 *nix 系统上,可以直接执行 pyvenv ./blog-env 来创建一个虚拟环境。在 Windows 系统上,则可以使用 python -m venv ./blog-env 来创建, 这个命令也可以用于 *nix 系统,推荐使用。

venv创建的虚拟环境,建议就在项目目录,这样使用起来更方便,没有记忆负担。

创建完成后 *nix 系统上, 使用 source ./blog-env/bin/activate 进入虚拟环境,window系统上,使用 Scripts\\activate.bat,效果如下:

1
2
➜  blog source ./blog-env/bin/activate
(blog-env) ➜  blog

注意在命令提示符之前新出现的 (blog-env) 标识进入了新的虚拟环境。

这样很方便就获得了一个隔离的python环境。

使用 pipenv

pipenvKenneth Reitz推出的python包依赖工具, kr就是大名鼎鼎requests的作者。pipenv号称Python Dev Workflow for Humans, 实力可见一斑。

介绍pipenv之前,我们先看venv存在的问题。我这里有一个django项目,使用django-rest-framework提供RestFul api服务, 利用jwt进行前后端认证,项目安装完后依赖大概如下:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
(wxsc) ➜  wordpress pip list
Package                 Version
----------------------- ----------
asn1crypto              0.24.0
certifi                 2018.10.15
cffi                    1.11.5
chardet                 3.0.4
coreapi                 2.3.3
coreschema              0.0.4
cryptography            2.3.1
diff-match-patch        20181111
Django                  2.0.5
django-crispy-forms     1.7.2
django-filter           2.0.0
django-formtools        2.1
django-import-export    1.1.0
django-reversion        3.0.0
djangorestframework     3.9.0
djangorestframework-jwt 1.11.0
et-xmlfile              1.0.1
future                  0.16.0
httpie                  1.0.0
httplib2                0.12.0
idna                    2.7
itypes                  1.1.0
jdcal                   1.4
Jinja2                  2.10
Markdown                3.0.1
MarkupSafe              1.1.0
odfpy                   1.3.6
openpyxl                2.5.10
pip                     18.1
pipenv                  2018.11.14
pycparser               2.19
Pygments                2.2.0
PyJWT                   1.6.4
PyMySQL                 0.9.2
pytz                    2018.5
PyYAML                  3.13
requests                2.20.1
setuptools              40.6.2
six                     1.11.0
tablib                  0.12.1
unicodecsv              0.14.1
uritemplate             3.0.0
urllib3                 1.24.1
virtualenv              16.1.0
virtualenv-clone        0.4.0
wheel                   0.32.2
xlrd                    1.1.0
XlsxWriter              1.1.2
xlwt                    1.3.0

前前后后大约安装了50个包,最后完全不清楚,那些是我直接安装的,那些是间接安装的,pipenv可以解决这个问题。

pipenv 安装很方便:

1
$ pip install pipenv

如果标准版本还是python2.7,则可以使用 pip3 install pipenv

pipenv使用起来也很方便。接下来我们一起了解这个过程。

创建一个新的工作目录myproject,使用下面命令创建虚拟环境,创建完成后目录下会生成一个Pipfile文件。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
$ pipenv --three
Creating a virtualenv for this project…
Pipfile: /private/tmp/myproject/Pipfile
Using /Library/Frameworks/Python.framework/Versions/3.7/bin/python3 (3.7.1) to create virtualenv…
✔ Complete
Using base prefix '/Library/Frameworks/Python.framework/Versions/3.7'
New python executable in /Users/tu/codes/venv/myproject-7Ev2diGY/bin/python3
Also creating executable in /Users/tu/codes/venv/myproject-7Ev2diGY/bin/python
Installing setuptools, pip, wheel...
done.
Running virtualenv with interpreter /Library/Frameworks/Python.framework/Versions/3.7/bin/python3
Virtualenv location: /Users/tu/codes/venv/myproject-7Ev2diGY
Creating a Pipfile for this project…

查看虚拟环境的实际目录,了解python命令路径(可以用于配合pycharm选择解释器)。

1
2
$ pipenv --venv
$ pipenv --py

pipenv 的虚拟环境会统一存放,不会在项目路径下

安装软件包。包安装完成后,会在项目路径下生成Pipfile.lock文件。

1
2
$ pipenv install requests
$ pipenv install django

注意: 这里不是使用 pip 进行包安装,而是使用 pipenv

查看项目依赖。视图比较清晰的描述了,项目依赖了2个包,每个包又分别依赖了其它的一些包。

1
2
3
4
5
6
7
8
➜  myproject2 pipenv graph
Django==2.1.3
  - pytz [required: Any, installed: 2018.7]
requests==2.20.1
  - certifi [required: >=2017.4.17, installed: 2018.10.15]
  - chardet [required: >=3.0.2,<3.1.0, installed: 3.0.4]
  - idna [required: >=2.5,<2.8, installed: 2.7]
  - urllib3 [required: >=1.21.1,<1.25, installed: 1.24.1]

重用requirements.txt文件。在项目目录下创建requirements.txt,内容参见上文。

1
$ pipenv install

pipenv 默认会读取本地目录,也可以使用-r参数指定requirements.txt位置。

pipenv 的依赖和 venv 有差异,可能直接导入 venv中的 requirements.txt 有一些问题,可以直接手工安装。

pipenv就简单介绍到这里,大家可以看pipenv使用指南。总的来说venv和pipenv各有优势吧,venv原生自带,简单方便,比较适合服务器上调试;pipenv,功能强大更适合本地调试。

Anaconda

科学计算领域,python著名的库pandasnumpymatplotlib, 然后还有图像处理和视觉这块的opencv,以及机器学习的tensorflow安装比较复杂,在这个领域一般使用anaconda的解决方案,其wiki介绍如下:

Anaconda 是一种Python语言的免费增值开源发行版,用于进行大规模数据处理、预测分析,和科学计算,致力于简化包的管理和部署。 Anaconda使用软件包管理系统Conda进行包管理。

我选择的是anaconda3,使用的iterm2,安装完成后会有路径问题,需要在~/.zshrc中添加:

1
export PATH="/anaconda3/bin:$PATH"

然后访问使用下面命令查看anaconda环境。

1
2
3
4
➜  ~ which conda
/anaconda3/bin/conda
➜  ~ conda --version
conda 4.5.11

创建虚拟环境,并进入虚拟环境:

1
2
3
4
5
6
7
conda create --name python36 python=3.6
➜  ~ source activate python36
(python36) ➜  ~
(python36) ➜  ~ python -V
Python 3.6.7 :: Anaconda, Inc.
(python36) ➜  ~ source deactivate
➜  ~

查看conda管理的环境列表:

1
2
3
4
5
➜  ~ conda info -e
# conda environments:
#
base                  *  /anaconda3
python36                 /anaconda3/envs/python36

Anaconda在个人研发过程中使用不多,如果想了解更多,可以看Anaconda 入门安装教程

docker时代的python环境

前面介绍的内容,都是在本地进行一些配置,创建各种环境。可是本地就一个,折腾几次后还是容易乱,docker这么强大,我们也可以用docker来玩python开发。

首先,我们编写hello.py,代码如下:

1
2
3
4
5
6
7
8
9
# -*- coding:utf-8 -*-


def test():
	print "Hello, python, docker"


if __name__ == "__main__":
	test()

然后执行下面命令:

1
docker run -it --rm --name docker-python2 -v "$PWD":/usr/src/myapp -w /usr/src/myapp python:2.7.16-alpine3.9 python hello.py

命令结果如下:

1
2
3
4
5
6
7
8
9
Unable to find image 'python:2.7.16-alpine3.9' locally
2.7.16-alpine3.9: Pulling from library/python
8e402f1a9c57: Already exists
d8cdc394c05b: Pull complete
1e2b4a75cc6b: Pull complete
2fbbf60d928e: Pull complete
Digest: sha256:46d6e67d464a2811efe60440248623b14cb6db273fac59631dd8bd9e13a77491
Status: Downloaded newer image for python:2.7.16-alpine3.9
Hello, python, docker

注意,初次执行会进行镜像文件下载,比较缓慢,下载成功后再次执行脚本就会非常迅速了。

这里的docker命令比较复杂,可以先不用管它的含义。我们继续编写hello3.py,代码如下:

1
2
3
4
5
6
7
8
9
# -*- coding:utf-8 -*-


def test():
	print("Hello, python, docker")


if __name__ == "__main__":
	test()

使用下面命令执行:

1
docker run -it --rm --name docker-python3 -v "$PWD":/usr/src/myapp -w /usr/src/myapp python:3.7.3-alpine3.9 python hello3.py

执行结果如下:

1
2
3
4
5
Unable to find image 'python:3.7.3-alpine3.9' locally
3.7.3-alpine3.9: Pulling from library/python
Digest: sha256:11568bb68bd375727e468ea5995f556139ff305eed9d8ee1d04b1a4a03a6486a
Status: Downloaded newer image for python:3.7.3-alpine3.9
Hello, python, docker

我们简单了解一下运行命令的含义:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
➜  python docker run --help
Usage:	docker run [OPTIONS] IMAGE [COMMAND] [ARG...]
  -i, --interactive                    Keep STDIN open even if not attached
  ...
  --rm                             Automatically remove the container when it exits
  ...
  -t, --tty                            Allocate a pseudo-TTY
  ...
  -v, --volume list                    Bind mount a volume
      --volume-driver string           Optional volume driver for the container
      --volumes-from list              Mount volumes from the specified container(s)
  -w, --workdir string                 Working directory inside the container

docker run -it --rm --name docker-python2 -v "$PWD":/usr/src/myapp -w /usr/src/myapp python:2.7.16-alpine3.9 python hello.py 翻译过来的意思大概是下面几点:

  1. 使用 python:2.7.16-alpine3.9 镜像启动容器,python表示镜像名称,2.7.16-alpine3.9表示版本标签。
  2. 容器名称命名为docker-python2,并且输出信息到当前终端,容器运行完成后自动删除。
  3. 容器使用数据卷,将当前目录和容器内的/usr/src/myapp目录进行映射。
  4. 设置/usr/src/myapp为工作目录,然后运行python hello.py命令。

这样经过上面几步,我们就使用docker容器执行了hello.py了。而且我们也有了2个镜像,可以分别执行python2和python3的代码。当然实际的工程中,只是执行一个py文件 有点杀鸡用牛刀的感觉,可以如果执行一个django项目,却是可以很好的保持开发环境和部署环境的一致。这部分内容,以后我会进行补充介绍。

提示:docker和venv/pipenv也可以配合使用,将虚拟环境创建在当前目录即可,留给大家动手探索吧。

回顾

最后,我们一起来简单回顾一下python虚拟环境:

  1. 使用python虚拟环境可以有效解决python语法版本差异及使用场景差异。
  2. 使用pip安装各种包。
  3. python3自带venv创建和管理各种环境。
  4. pipenv是一种混合了pip和venv的环境管理方法。
  5. 使用anaconda管理python科学计算环境。
  6. 可以使用docker等方式使用python环境。

附录

如果继续使用pyhon2,可以参靠下面部分内容。python2的虚拟环境 virtualenv&virtualenvwrapper。

virtualenv 是一个创建隔绝的Python环境的工具,可以创建一个包含所有必要的可执行文件的文件夹,用来使用Python工程所需的包。

virtualenv安装非常简单,直接使用下面命令:

1
pip install virtualenv

可能会遇到权限问题,可以使用sudo提权

但是virtualenv有一个弊端是,每次会在当前目录创建venv)(pycharm默认使用这种方式),每次需要自己记住不同的虚拟机目录,使用起来不太方便。 这里我们直接跳过virtualenv的使用,继续使用其扩展包virtualenvwrapper

virtualenvwrapper安装也非常简单,直接使用下面命令:

1
pip install virtualenvwrapper

! 注意:windows用户使用的命令是 pip install virtualenvwrapper-win 后面带-win

使用virtualenvwrapper需要先设置环境变量,我使用的iTerm2配置的zshrc,需要在用户根目录下的.zshrc中增加下面2行:

1
2
export WORKON_HOME=~/codes/venv
source /usr/local/bin/virtualenvwrapper.sh

配置好环境变量后,退出重启term生效。

创建一个flask开发环境

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
mkvirtualenv flask
Using base prefix '/Library/Frameworks/Python.framework/Versions/2.7'
New python executable in /Users/tu/codes/venv/flask/bin/python
Also creating executable in /Users/tu/codes/venv/flask/bin/python
Installing setuptools, pip, wheel...done.
virtualenvwrapper.user_scripts creating /Users/tu/codes/venv/flask/bin/predeactivate
virtualenvwrapper.user_scripts creating /Users/tu/codes/venv/flask/bin/postdeactivate
virtualenvwrapper.user_scripts creating /Users/tu/codes/venv/flask/bin/preactivate
virtualenvwrapper.user_scripts creating /Users/tu/codes/venv/flask/bin/postactivate
virtualenvwrapper.user_scripts creating /Users/tu/codes/venv/flask/bin/get_env_details
(flask) ➜  pytest

注意创建好虚拟环境后会自动进入该环境,命令提示符前会显示当前环境的名称,例如(flask) 字样。

再创建一个爬虫的开发环境

1
2
mkvirtualenv spider
...

这样你可以在flask的环境中安装flask库,spider的环境中安装requests库,而不用担心依赖冲突。

如果你希望创建一个python3版本的环境,需要先行安装好python3,然后使用下面命令:

1
2
# -p 参数指定版本,可以使用python3的绝对路径
mkvirtualenv py3studio -p python3

其它常用命令,如下:

1
2
3
4
5
6
7
8
# 列出env列表
workon
# 进入指定的env
workon name
# 退出当前env
deactivate
# 删除env
rmvirtualenv name

ok,我们使用pip安装virtualenv和virtualenvwrapper,顺利的解决了不同版本的python问题,可以愉快的开发(玩耍)了。