mac下Python关于venv 的使用

参考

廖雪峰 virtualenv
Python 项目管理的利器:虚拟环境 venv 的使用

环境

  • Mac

Python环境

virtualenv 用于解决环境依赖而存在,通过 virtualenv 命令可以生成项目的独立依赖环境。
如果本地有多个版本的Python,需要对不同版本的Python单独安装virtualenv

不清楚管理多个版本Python的,可以参考我的另一篇Mac管理多版本Python

安装virtualenv

不久之前,重装了系统,发现system下的Python(系统自带的版本)默认没有安装pip

wuxiaoxindeMac-mini:~ wuxiaoxin$ pyenv versions
* system (set by /Users/wuxiaoxin/.pyenv/version)
  3.7.4
wuxiaoxindeMac-mini:~ wuxiaoxin$ pip -V
pyenv: pip: command not found

The `pip' command exists in these Python versions:
  3.7.4

先安装下pip,终端下执行:

sudo easy_install pip

安装完毕如下:

...
Installed /Library/Python/2.7/site-packages/pip-19.2.2-py2.7.egg
Processing dependencies for pip
Finished processing dependencies for pip

wuxiaoxindeMac-mini:~ wuxiaoxin$ pip -V
pip 19.2.2 from /Library/Python/2.7/site-packages/pip-19.2.2-py2.7.egg/pip (python 2.7)

安装virtualenv

pip install virtualenv

出现这样的警告:

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. More details about Python 2 support in pip, can be found at https://pip.pypa.io/en/latest/development/release-process/#python-2-support

说是Python 2.7将于2020年1月1日结束它的生命。。。
看来Python3大势已定。

$ pip install virtualenv
Collecting virtualenv
  Using cached https://files.pythonhosted.org/packages/7e/1b/6c00d57127608793e16e8b7f813e64d58a1938505c42fe190d1386ab41e1/virtualenv-16.4.0-py2.py3-none-any.whl
Installing collected packages: virtualenv
Successfully installed virtualenv-16.4.0

如果出现这样的错误:

ERROR: Could not install packages due to an EnvironmentError: [Errno 13] Permission denied: '/Library/Python/2.7/site-packages/virtualenv.pyc'
Consider using the --user option or check the permissions.

应该是权限问题,根据提示加上--user试试。

pip install virtualenv --user

安装成功:

Successfully installed virtualenv-16.7.2

查看当前Python版本:system ,已经安装的库:

pip list

$ pip list
Package                                Version 
-------------------------------------- --------
altgraph                               0.10.2  
bdist-mpkg                             0.5.0   
bonjour-py                             0.3     
macholib                               1.5.1   
matplotlib                             1.3.1   
modulegraph                            0.10.4  
numpy                                  1.8.0rc1
pip                                    19.2.2  
py2app                                 0.7.3   
pyobjc-core                            2.5.1   
pyobjc-framework-Accounts              2.5.1   
pyobjc-framework-AddressBook           2.5.1   
pyobjc-framework-AppleScriptKit        2.5.1   
pyobjc-framework-AppleScriptObjC       2.5.1   
pyobjc-framework-Automator             2.5.1   
pyobjc-framework-CFNetwork             2.5.1   
pyobjc-framework-Cocoa                 2.5.1   
pyobjc-framework-Collaboration         2.5.1   
pyobjc-framework-CoreData              2.5.1   
pyobjc-framework-CoreLocation          2.5.1   
pyobjc-framework-CoreText              2.5.1   
pyobjc-framework-DictionaryServices    2.5.1   
pyobjc-framework-EventKit              2.5.1   
pyobjc-framework-ExceptionHandling     2.5.1   
pyobjc-framework-FSEvents              2.5.1   
pyobjc-framework-InputMethodKit        2.5.1   
pyobjc-framework-InstallerPlugins      2.5.1   
pyobjc-framework-InstantMessage        2.5.1   
pyobjc-framework-LatentSemanticMapping 2.5.1   
pyobjc-framework-LaunchServices        2.5.1   
pyobjc-framework-Message               2.5.1   
pyobjc-framework-OpenDirectory         2.5.1   
pyobjc-framework-PreferencePanes       2.5.1   
pyobjc-framework-PubSub                2.5.1   
pyobjc-framework-QTKit                 2.5.1   
pyobjc-framework-Quartz                2.5.1   
pyobjc-framework-ScreenSaver           2.5.1   
pyobjc-framework-ScriptingBridge       2.5.1   
pyobjc-framework-SearchKit             2.5.1   
pyobjc-framework-ServiceManagement     2.5.1   
pyobjc-framework-Social                2.5.1   
pyobjc-framework-SyncServices          2.5.1   
pyobjc-framework-SystemConfiguration   2.5.1   
pyobjc-framework-WebKit                2.5.1   
pyOpenSSL                              0.13.1  
pyparsing                              2.0.1   
python-dateutil                        1.5     
pytz                                   2013.7  
scipy                                  0.13.0b1
setuptools                             18.5    
six                                    1.4.1   
virtualenv                             16.7.2  
xattr                                  0.6.4

新建一个文件夹test,test作为工程文件夹,在该文件夹中创建venv环境。
使用virtualenv命令,可以自动创建venv环境。

可以发现virtualenv已经安装,但是会提示无此命令:

wuxiaoxindeMac-mini:7 wuxiaoxin$ virtualenv --no-site-packages venv
-bash: virtualenv: command not found

可以再执行一次安装命令,终端会提示virtualenv的安装路径:

pip install virtualenv
Requirement already satisfied: virtualenv in /Users/wuxiaoxin/Library/Python/2.7/lib/python/site-packages (16.7.2)

顺着这条路径
/Users/wuxiaoxin/Library/Python/2.7/lib/python/site-packages
可以找到virtualenv命令文件所在路径
/Users/wuxiaoxin/Library/Python/2.7/bin/virtualenv
这个命令virtualenv可以成功执行。至于为什么安装后不会自动设置环境变量,原因不详。

这时候有两种方式可以尝试下

  • 将命令所在路径加载到 PATH
    可以通过修改.bash_profile文件来实现,open ~/.bash_profile
export VIRTUALENV_PATH=/Users/wuxiaoxin/Library/Python/2.7/bin
export PATH=$VIRTUALENV_PATH:$PATH

重启终端,查看PATH,发现路径已经成功加到PATH

wuxiaoxindeMac-mini:~ wuxiaoxin$ echo $PATH
/Users/wuxiaoxin/Library/Python/2.7/bin:/Users/wuxiaoxin/.pyenv/shims:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin

测试成功:

$ virtualenv
You must provide a DEST_DIR
Usage: virtualenv [OPTIONS] DEST_DIR

Options:
  --version             show program's version number and exit
... (此处省略后面内容)
  • 设置命令的软连接
    如果不通过修改.bash_profile达到设置PATH的话。可以直接设置软连接,其实就是将命令拷贝一个替身到/usr/local/bin下。

ln –s 源文件 目标文件

ln -s /Users/wuxiaoxin/Library/Python/2.7/bin/virtualenv /usr/local/bin/virtualenv

这里其实不需要考虑Python版本问题,virtualenv命令已经限定了Python版本。
如果你将.bash_profile中关于virtualenv的路径设置注释掉,重启终端,再执行virtualenv,会发现:

wuxiaoxindeMac-mini:~ wuxiaoxin$ pyenv versions
* system (set by /Users/wuxiaoxin/.pyenv/version)
  3.7.4
wuxiaoxindeMac-mini:~ wuxiaoxin$ virtualenv
pyenv: virtualenv: command not found

The `virtualenv' command exists in these Python versions:
  3.7.4
wuxiaoxindeMac-mini:~ wuxiaoxin$ pyenv global 3.7.4
wuxiaoxindeMac-mini:~ wuxiaoxin$ python -V
Python 3.7.4
wuxiaoxindeMac-mini:~ wuxiaoxin$ virtualenv
You must provide a DEST_DIR
Usage: virtualenv [OPTIONS] DEST_DIR

Options:
  --version             show program's version number and exit
...(此处省略后面内容)

现在可以正常使用了:

wuxiaoxindeMac-mini:test wuxiaoxin$ virtualenv --no-site-packages venv
New python executable in /Users/wuxiaoxin/Desktop/test/venv/bin/python
Installing setuptools, pip, wheel...
done.
test项目独立依赖环境

加上了参数--no-site-packages,这样,已经安装到系统Python环境中的所有第三方包都不会复制过来,这样,我们就得到了一个不带任何第三方包的“干净”的Python运行环境。

实测不加这么个参数,直接执行virtualenv venv也是一样的效果呢。
如何知道?启动该虚拟环境,在该环境下pip list即可一目了然。
比如我的一个虚拟环境安装在这个路径下:
/Users/vampire/Desktop/test3/venv
那么可以这样启动虚拟环境:

source /Users/vampire/Desktop/test3/venv/bin/activate

如图,已经启动虚拟环境:


已经进入虚拟环境.jpg

如下,test3中使用参数--no-site-packages,test4中不使用参数--no-site-packages,实测可以看出,--no-site-packages参数加上和不加上,效果一样:

效果一样.jpg

只有一种可能,--no-site-packages是默认参数。
终端下执行virtualenv可以看到:

果然--no-site-packages是默认参数.jpg

那么 --system-site-packages 就是它的对立参数了,测试下:

全局依赖参数.jpg

可以看到,安装在系统的Python环境中的库,也复制到这个虚拟环境中来了。

还需要注意的是这个参数:

-p PYTHON_EXE, --python=PYTHON_EXE
The Python interpreter to use, e.g.,
--python=python3.5 will use the python3.5 interpreter
to create the new environment. The default is the
interpreter that virtualenv was installed with
(/usr/bin/python)

可以看出,执行virtualenv命令生成的虚拟环境,默认是依据
/usr/bin/python目录下的Python环境。其实也就是当前安装virtualenv所属的Python的版本。

当前电脑下有两个Python环境:

wuxiaoxindeMac-mini:test1 wuxiaoxin$ pyenv versions
* system (set by /Users/wuxiaoxin/.pyenv/version)
  3.7.4

如果这样执行命令,会怎样?

wuxiaoxindeMac-mini:test1 wuxiaoxin$ virtualenv  --python=python3.7 venv
Running virtualenv with interpreter /Users/wuxiaoxin/.pyenv/shims/python3.7
pyenv: python3.7: command not found

The `python3.7' command exists in these Python versions:
  3.7.4

如果是这样限制的话,需要创建源自python3.7.4版本的依赖环境,直接使用pyenv进行切换即可,virtualenv不需要带这个参数--python了。

终端下进入和退出venv虚拟环境:

假设一个新的venv虚拟环境所在的目录如下:
/Users/vampire/Desktop/test/venv
venv目录中包含如下文件夹:

  • bin
  • include
  • lib
    而该入口文件正是处于bin文件中的activate文件,那么进入虚拟环境的命令如下:
source /Users/vampire/Desktop/test/venv/bin/activate

退出虚拟环境的命令:

deactivate #这个是全局的命令,任何路径下执行都行

venv环境下安装库

终端下先进入该venv环境,再执行pip install 安装。

venv下安装库.png

关于 venv 移动位置

一般我们使用virtualenv的目的是为了让一个工程拥有独立的依赖环境。
我们会把virtualenv生成的环境venv放置在工程路径下。
如果我们移动了这个工程的路径,venv路径也会随之改变,因此注意修改这个命令文件
activate,打开这个文件,你会发现其实就是bash shell脚本,该命令的路径也固定写在其中:

venv路径

因此一旦移动venv,记得修改venv/bin/activate文件中的路径。如果是复制了venv,也需要对复制venvvenv/bin/activate文件中的路径,原venv/bin/activate保持不变。

推荐阅读更多精彩内容