为什么virtualenv会从我的shell中继承$PYTHONPATH?

8 投票
3 回答
10513 浏览
提问于 2025-04-18 12:10

我正在把我的工具从python2迁移到python3.4,使用的是Ubuntu 14.04系统。到目前为止,我做了以下几件事:

  1. 在我的zshrc文件中把python设置成python3,只对我个人有效
  2. 在系统上安装了pip3(不过我其实会使用虚拟环境,所以也不太会用到它)
  3. 把我的虚拟环境管理工具的“make”命令改成了mkvirtualenv --python=/usr/bin/python3(下面的'workon'命令用'v'来调用)

现在有个奇怪的情况,你可以在下面看到,虽然我在虚拟环境中运行python3,但它还是继承了我的$PYTHONPATH,这个变量还是为python2设置的路径。这在我的虚拟环境中安装或运行程序时会造成问题,因为python3的路径在旧的python2路径之后,所以我的程序先导入的是python2的模块。在启动虚拟环境之前把$PYTHONPATH清空成''可以解决这个问题,这样我的程序就能正常运行了。不过我有几个问题:

  1. 在虚拟环境中继承$PYTHONPATH是正常的吗?这不是违背了虚拟环境的目的吗?
  2. 既然python内部已经处理了自己的路径,为什么还要在shell中设置$PYTHONPATH这个环境变量呢?
  3. 我使用$PYTHONPATH的方式对吗?我应该只在'zshrc'中设置我的个人路径($HOME/dev),而不包括冗余的'/usr/local/lib/'路径吗?
  4. 我可以在调用虚拟环境之前很容易地导出一个不同的python3路径,使用完后再重置,但这样做是解决问题的最好方法吗?
    ○ echo $PYTHONPATH
    /usr/local/lib/python2.7/site-packages:/usr/local/lib/python2.7/dist-packages:/usr/lib/python2.7/dist-packages:/home/brian/dev

    brian@zeus:~/.virtualenvs
    ○ python2
    Python 2.7.6 (default, Mar 22 2014, 22:59:56)
    [GCC 4.8.2] on linux2
    Type "help", "copyright", "credits" or "license" for more information.
    >>> import sys, pprint
    >>> pprint.pprint(sys.path)
    ['',
     '/usr/local/lib/python2.7/dist-packages/pudb-2013.3.4-py2.7.egg',
     '/usr/local/lib/python2.7/dist-packages/Pygments-1.6-py2.7.egg',
     '/usr/local/lib/python2.7/dist-packages/urwid-1.1.1-py2.7-linux-x86_64.egg',
     '/usr/local/lib/python2.7/dist-packages/pythoscope-0.4.3-py2.7.egg',
     '/usr/local/lib/python2.7/site-packages',
     '/usr/local/lib/python2.7/dist-packages',
     '/usr/lib/python2.7/dist-packages',
     '/home/brian/dev',
     '/usr/lib/python2.7',
     '/usr/lib/python2.7/plat-x86_64-linux-gnu',
     '/usr/lib/python2.7/lib-tk',
     '/usr/lib/python2.7/lib-old',
     '/usr/lib/python2.7/lib-dynload',
     '/usr/lib/python2.7/dist-packages/PILcompat',
     '/usr/lib/python2.7/dist-packages/gst-0.10',
     '/usr/lib/python2.7/dist-packages/gtk-2.0',
     '/usr/lib/pymodules/python2.7',
     '/usr/lib/python2.7/dist-packages/ubuntu-sso-client',
     '/usr/lib/python2.7/dist-packages/ubuntuone-client',
     '/usr/lib/python2.7/dist-packages/ubuntuone-storage-protocol',
     '/usr/lib/python2.7/dist-packages/wx-2.8-gtk2-unicode']
    >>>

    brian@zeus:~/.virtualenvs
    ○ v py3venv
    (py3venv)
    brian@zeus:~/.virtualenvs
    ○ python3
    Python 3.4.0 (default, Apr 11 2014, 13:05:11)
    [GCC 4.8.2] on linux
    Type "help", "copyright", "credits" or "license" for more information.
    >>> import sys, pprint
    >>> pprint.pprint(sys.path)
    ['',
     '/usr/local/lib/python2.7/site-packages',
     '/usr/local/lib/python2.7/dist-packages',
     '/usr/lib/python2.7/dist-packages',
     '/home/brian/dev',
     '/home/brian/.virtualenvs/py3venv/lib/python3.4',
     '/home/brian/.virtualenvs/py3venv/lib/python3.4/plat-x86_64-linux-gnu',
     '/home/brian/.virtualenvs/py3venv/lib/python3.4/lib-dynload',
     '/usr/lib/python3.4',
     '/usr/lib/python3.4/plat-x86_64-linux-gnu',
     '/home/brian/.virtualenvs/py3venv/lib/python3.4/site-packages']
    >>>
    (py3venv)

3 个回答

1

$PYTHONPATH 出现在你的虚拟环境中,是因为这个虚拟环境只是你命令行环境的一部分,而你(在某个地方)告诉你的命令行要把 PYTHONPATH 的值传递给子命令行。

使用虚拟环境的一个好处是,你不需要在 PYTHONPATH 中添加额外的目录,但看起来你不小心把它当成了一个全局设置(对所有命令行都有效),其实它更适合用作每个项目的设置。

编辑于2023年10月2日: 由于在开发机器上不建议以任何方式修改系统的 Python*,学习使用虚拟环境可以让你轻松地将不同项目的依赖分开,从而避免它们之间的冲突。

从 Python 3.7 开始,你可以用命令 python3.x -m venv pathname 创建一个虚拟环境。创建后,你可以用 source pathname/bin/activate(大多数命令行都可以这样做,其他的命令行也有替代方法)来激活它,使用 deactivate 来停用它,或者直接结束命令行进程。用完后,只需 rm -rpathname 来删除它。

不要像我一样感到害怕——我浪费了一年才开始使用它们!

* 你永远不知道你的系统依赖它来做什么!

3

你还可以通过在你的虚拟环境的 /bin/activate 文件中添加内容来改变 Python 的路径:

export PYTHONPATH="/your/path"

更详细的解释可以在 这里 找到:

引用:

为了在你退出虚拟环境时把路径恢复到原来的值,你可以在之前提到的那行代码之前添加:

export OLD_PYTHONPATH="$PYTHONPATH"

然后在你的 bin/postdeactivate 脚本中添加以下这一行。


你可能还想看看 这个 答案,它讲的是如何使用 add2virtualenv 来添加目录。

1

我偶然发现了这个回答,它刚好解决了我现在的问题。简单来说,设置$PYTHONPATH是可选的,它只是为了方便用户。这个变量里应该只放用户想要添加到Python路径中的额外路径,这样用户就不需要在Python里手动设置这些路径,只为从终端运行脚本。

所以为了处理我上面提到的问题,我在我的zshrc文件里把$PYTHONPATH设置成了我额外的文件夹'$HOME/dev',没有其他的路径。这样就消除了我路径中对python2的引用,我的所有python3程序在虚拟环境中都能正常启动了。

撰写回答