【问题标题】:How to prepend a path to sys.path in Python?如何在 Python 中添加 sys.path 的路径?
【发布时间】:2015-10-03 12:40:17
【问题描述】:

问题描述:

使用 pip,我升级到了最新版本的 requests(版本 2.7.0,pip show requests 提供了位置 /usr/local/lib/python2.7/dist-packages)。但是,当我在交互式命令行中 import requests 并打印 requests.__version__ 时,我看到的是 2.2.1 版。事实证明,Python 使用的是预装的 Ubuntu 版本的请求(requests.__file__/usr/lib/python2.7/dist-packages/requests/__init__.pyc -- 不是 /user/local/lib/...)。

根据我的调查,这个事实是由 Ubuntu 对 Python 搜索路径(我运行 Ubuntu 14.04)的更改引起的,方法是在 Ubuntu 的 Python 包的路径前添加(对于我的机器,这发生在 usr/local/lib/python2.7/dist-packages/easy-install.pth)。就我而言,这会导致使用与 Ubuntu 预打包的 apt-get 版本的请求,而不是我想要使用的 pip 版本。

我在寻找什么:

我想在 Ubuntu 的 Python 安装目录的路径之前将 pip 的安装目录路径全局添加到 Python 的搜索路径 (sys.path)。由于我的许多 Python 脚本中都使用了请求(以及许多其他包),因此我不想手动更改我机器上每个文件的搜索路径。

不满意的解决方案 1:使用 virtualenv

使用virtualenv 会对我的机器造成不必要的更改,因为我必须重新安装全局存在的每个包。我只想从 Ubuntu 的包升级到 pip 的包。

不满意的解决方案 2:更改 easy-install.pth

由于每次使用 easy-install 时都会覆盖 easy-install.pth,因此如果安装了新软件包,我对 easy-install.pth 的更改将被删除。这个问题让我的机器上的包很难维护。

不满意(但目前为止最好的一个)解决方案 3:添加单独的 .pth 文件

在与 easy-install.pth 相同的目录中,我添加了一个 zzz.pth 内容:

import sys; sys.__plen = len(sys.path)
/usr/lib/python2.7/dist-packages/test_dir
import sys; new=sys.path[sys.__plen:]; del sys.path[sys.__plen:]; p=getattr(sys,'__egginsert',0); sys.path[p:p]=new; sys.__egginsert = p+len(new)

此文件在 Python 启动时由 site.py 读取。由于它的文件名在字母数字上位于easy-install.pth 之后,因此它随后被site.py 使用。总而言之,文件的第一行和最后一行将路径添加到sys.path(这些行取自easy-install.pth)。

我不喜欢这个解决方案如何依赖文件名的字母数字顺序来正确放置新路径。

PYTHONPATH 位于 Ubuntu 的路径之后

Stack Overflow 上的Another answer 对我不起作用。我的 PYTHONPATH 路径位于 easy-install.pth 中的路径之后,它使用我在“不满意的解决方案 3”中提到的相同代码来添加其路径。

提前谢谢你!

【问题讨论】:

  • pip选对了吗python
  • 你有没有考虑过使用apt-get来移除预打包的版本?
  • 报告一个针对 Ubuntu 的错误,即用户的决定没有得到尊重。
  • 你是手动安装python-requests,还是依赖它?
  • @aragilar 我们直接通过 pip 安装请求。

标签: python ubuntu pip easy-install pythonpath


【解决方案1】:

不建议这样做,因为它会硬编码路径并难以在其他地方运行脚本,但您可以这样做

>>> import sys
>>> sys.path.insert(0,'/home/anand/')
>>> print(sys.path)
['/home/anand/', '', '/usr/local/lib/python2.7/dist-packages/_pdbpp_path_hack', '/usr/local/lib/python2.7/dist-packages/goose-0.0.1-py2.7.egg', '/usr/local/lib/python2.7/dist-packages/jieba-0.33-py2.7.egg', '/usr/local/lib/python2.7/dist-packages/cssselect-0.9.1-py2.7.egg', '/usr/local/lib/python2.7/dist-packages/nanoservice-0.1.5-py2.7.egg', '/usr/local/lib/python2.7/dist-packages/nanomsg-1.0a2-py2.7-linux-x86_64.egg', '/usr/local/lib/python2.7/dist-packages/msgpack_python-0.4.2-py2.7-linux-x86_64.egg', '/usr/local/lib/python2.7/dist-packages/DecisionTree-2.2.5-py2.7.egg', '/usr/local/lib/python2.7/dist-packages/nudepy-0.2-py2.7.egg', '/usr/local/lib/python2.7/dist-packages/wsgilog-0.3-py2.7.egg', '/usr/local/lib/python2.7/dist-packages/distribute-0.7.3-py2.7.egg', '/usr/local/lib/python2.7/dist-packages/PIL-1.1.7-py2.7-linux-x86_64.egg', '/usr/local/lib/python2.7/dist-packages/MySQL_python-1.2.5-py2.7-linux-x86_64.egg', '/usr/local/lib/python2.7/dist-packages/munkres-1.0.7-py2.7.egg', '/usr/local/lib/python2.7/dist-packages/parsedatetime-1.4-py2.7.egg', '/usr/local/lib/python2.7/dist-packages/argparse-1.3.0-py2.7.egg', '/usr/local/lib/python2.7/dist-packages/tusker-0.1-py2.7.egg', '/usr/local/lib/python2.7/dist-packages/SQLAlchemy-1.0.3-py2.7-linux-x86_64.egg', '/usr/local/lib/python2.7/dist-packages/numpy-1.9.2-py2.7-linux-x86_64.egg', '/usr/local/lib/python2.7/dist-packages/turkic-0.2.5-py2.7.egg', '/usr/local/lib/python2.7/dist-packages/scikits.bootstrap-0.3.2-py2.7.egg', '/usr/local/lib/python2.7/dist-packages/pyvision-0.1-py2.7-linux-x86_64.egg', '/home/anand/playspace/languages/python_pkgs/ets', '/usr/local/lib/python2.7/dist-packages/Scrapy-1.1.0dev1-py2.7.egg', '/usr/lib/python2.7/dist-packages', '/home/anand/playspace', '/home/anand/workspace/pyvision/src', '/home/anand/playspace/yapf', '/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/local/lib/python2.7/dist-packages', '/usr/local/lib/python2.7/dist-packages/Orange/orng', '/usr/local/lib/python2.7/dist-packages/PIL', '/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/wx-3.0-gtk2']
>>>

在此之后,您的导入将先查看前置路径,然后再查看其他任何位置。

【讨论】:

  • “这个不推荐……” 那你为什么推荐呢?那么推荐的方式是什么?
  • 我并不是说这不是推荐的方式。我的意思是,在 99.9% 的情况下不建议将自定义路径添加到 python 路径。几乎没有充分的理由这样做。 OP 的问题是一个特例,可能与以后的 ubuntu 版本不再相关。
  • 示例用例:我从 GitHub 克隆了我想要探索的 Python 包的源代码(例如插入断点、打印语句、测试修改)。我已经安装了这个包,我不想卸载它,安装我的测试等。我可以在测试脚本中使用这种技术来专门更改包副本,而不会影响其他任何东西。它在这里很有用,但绝对不是运行代码的一般方式。
  • 添加 sys.path 对 pylint --init-hook 很有用。
【解决方案2】:

您不需要弄乱 pip 的路径,根据我的经验,python 实际上会自动处理它的路径。看来您安装了两个蟒蛇。如果你输入:

which pip
which python

你看到了什么路径?如果它们不在同一个 /bin 文件夹中,那就是你的问题。我猜你正在运行的python(可能是原始系统)没有安装它自己的pip。您可能只需要确保您要运行的 python 的路径应该位于 .bashrc 或 .zshrc 中的 /usr/bin 之前

如果这是正确的,那么你应该看到:

which easy_install

与您正在使用的 python 安装共享相同的路径,可能在 /usr/local/bin 下。然后运行:

easy_install pip

然后开始为您正在使用的 python 安装正确的包。

【讨论】:

  • 我试图更改我的 Python 二进制文件在启动时使用的搜索路径。无论我使用什么二进制文件,确定搜索路径的规则都应该是一样的。
  • 嘿@max,我明白,但如果你安装了不同版本的python,那很危险。您应该在每个 python 旁边安装正确的 pip,然后将为该 python 安装正确的包。如果你不这样做,那么你的 python 会指向错误的版本,那会很糟糕。
  • 我必须同意@fivetentaylor 的观点。我有一个项目,我必须在其上使用 Python 3.X,当您安装该版本时,您会获得该版本 Python 的 pip。有一个python, python2, python2.7, python3, python3.4,然后是pip, pip2, pip2.7, pip3, pip3.4。 2 的安装到 dist-packagesPy2 和 3 的安装到 Py3 的一个。如果你想为 Python 3.4 安装一个包,那么你可以使用 python3.4 -m pip install <package>pip3.4 install <package>' and it will install in 3.4's dist-packages`。
  • 你正在运行的任何版本的python的解释器都将从它的dist-packages版本导入,你会得到正确的。我个人没有使用过 virtualenv,但从我读过的内容来看,这似乎是 Python 开发人员建议的多 Python 开发环境的方式。
  • 这不能解决问题,easy_installpip 以相同的方式对它们的命令进行版本控制。除非您使用 virtualenvs 管理您的 PYTHONPATHPATH,否则您将不断遇到问题。
【解决方案3】:

回答直接问题

您可以在您的site-packages 目录中创建一个名为sitecustomize 的目录。我们将把它变成一个sitecustomize 模块,如here(Python 2 here)所述。具体来说:

尝试导入名为 sitecustomize 的模块,该模块可以执行任意特定于站点的自定义。它通常由系统管理员在您的站点包目录中创建。

sitecustomize 目录中创建一个名为__init__.py 的文件,并在其中添加您要执行的操作。一个非常简单的例子是:

import sys
sys.path = ['/your/path/to/pip/install'] + sys.path

在你的情况下,我认为your/path... 将是/usr/local/lib/python2.7/dist-packages。您可能想做一些更复杂的事情,但这粗略地添加到 sys.path 之前,并且在 python 启动时运行(例如,在命令行中启动解释器,或从文件运行 python 脚本)。

警告

我不是这样做的大力倡导者 - 这是做你想做的事的一种直率的方式。但是你特别说使用 virtualenv 对你来说是不可取的,你想“全局”进行更改,我认为这会满足你的要求。

对潜在问题的思考

我认为@fivetentaylor 的answer 在这里是正确的——看来您正在使用来自一个安装的pip 和另一个安装的python 可执行文件。通过弄乱路径来掩盖这一点可能会很快变得非常混乱。我肯定会确保每次安装python 都有一个单独的pip 并且你使用它。这应该保持单独安装的目录结构分开。否则,您将强制一个安装使用来自不同安装目录的包。技术上没问题,但逻辑上有点混乱。

【讨论】:

  • 我有一个设置,他们需要一起使用 easy_install 和 pip。正如我所见,这是唯一的方法。为我节省了至少半天时间。
  • @binithb 很高兴我能帮上忙 :)
【解决方案4】:

使用 virtualenv 会对我的机器造成不必要的更改,因为我必须重新安装全局存在的每个包。我只想从 Ubuntu 的包升级到 pip 的包。

不,你可以使用--system-site-packages

编辑

# make your new virtualenv
user@darkstar:~$ mkvirtualenv --system-site-packages max
(max)user@darkstar:~$ python
>>> pprint(sys.path)
['',
 '/home/user/.virtualenvs/max/lib64/python27.zip',
 '/home/user/.virtualenvs/max/lib64/python2.7',
 '/home/user/.virtualenvs/max/lib64/python2.7/plat-linux2',
 '/home/user/.virtualenvs/max/lib64/python2.7/lib-tk',
 '/home/user/.virtualenvs/max/lib64/python2.7/lib-old',
 '/home/user/.virtualenvs/max/lib64/python2.7/lib-dynload',
 '/usr/lib64/python2.7',
 '/usr/lib/python2.7',
 '/usr/lib64/python2.7/lib-tk',
 '/home/user/.virtualenvs/max/lib/python2.7/site-packages',
 '/usr/lib64/python2.7/site-packages/google_api_python_client-1.2-py2.7.egg',
 '/usr/lib64/python2.7/site-packages',
 '/usr/lib64/python2.7/site-packages/PIL',
 '/usr/lib64/python2.7/site-packages/gtk-2.0',
 '/usr/lib64/python2.7/site-packages/IPython/extensions']

如您所见,这个 virtualenv 的路径包括系统路径。 为了检查它是否正常工作,我在制作 virtualenv 之后在系统范围内安装了一个包

root@darkstar:~: pip install igraph
Collecting igraph
  Downloading igraph-0.1.8-py2.py3-none-any.whl (119kB)
    100% |████████████████████████████████| 122kB 1.7MB/s
Collecting ipython (from igraph)
  Downloading ipython-3.2.1-py2-none-any.whl (3.4MB)
    100% |████████████████████████████████| 3.4MB 203kB/s 
Installing collected packages: ipython, igraph
Successfully installed igraph-0.1.8 ipython-3.2.1
root@darkstar:~: python -c 'print __import__("igraph")'
<module 'igraph' from '/usr/lib64/python2.7/site-packages/igraph/__init__.pyc'>

(max)user@darkstar:max$ python -c 'print __import__("igraph")'
<module 'igraph' from '/usr/lib64/python2.7/site-packages/igraph/__init__.pyc'>

显然,安装在 virtualenv 中的内容优先于系统范围的库。

我相信这可以满足您的需求。

【讨论】:

  • 您能否详细说明您的解决方案?
【解决方案5】:

嗯,其他人提出的替代方案是非常可接受的,甚至可能更好。但是,如果您打算使用 sys.path() 方式,则只需将其视为列表并使用 insert 方法。

import sys
sys.path.insert(0, "path_to_pip") 
from subprocess import call
call("sudo pip install requests") 

【讨论】:

    【解决方案6】:

    我会按照site.py 文档中的说明使用sitecustomize 执行此操作。此文件是在配置初始sys.path 后导入的,您可以根据需要使用它以任意方式更改sys.path

    我已将它用作系统管理员来包含自定义发布位置,它的工作非常出色。

    https://docs.python.org/2/library/site.html

    【讨论】:

      【解决方案7】:

      虽然bufh's 的回答现在可以解决您的问题,但您可能会发现还有其他一些您不想使用 Ubuntu 提供的版本的软件包。所以这就是为什么你要使用 virtualenvs 来管理包的版本(而不是试图覆盖系统版本)。

      如您所见,sys.path 的顺序设置了查找 python 包的顺序。这意味着更改 sys.path 会影响 python 脚本如何找到它们的导入,包括您编写的脚本以及 Ubuntu 提供的脚本。鉴于在 Ubuntu 程序中使用了 python 脚本,可以通过更改 Ubuntu 程序使用的 python 包版本(这就是 dist-packages 存在的原因)以有趣的方式“破坏”Ubuntu。

      为了避免这种情况,创建了 virtualenv,它有效地允许使用不同的包集。现在有很多实用程序可以更轻松地使用和管理 virtualenvs。您可能最感兴趣的是pipsi,它为每个脚本创建一个virtualenv,并且无需激活它。

      【讨论】:

        【解决方案8】:

        从表面上看,Ubuntu 正在使用 here 记录的包路径配置文件来设置它安装的任何包。

        查看site.py,我看到有一个特定的路径解析顺序,它在解析站点包目录时调用配置文件。

        我认为这为您提供了三个我可以看到的选项:

        1. 根据@bufh 的回答使用 virtualenv --system-site-packages。
        2. 使用pip user installs在标准站点包之前的路径中设置您需要的包。
        3. 使用 sitecustomize 重写您的 sys.path(例如,首先放置您的本地目录)。

        【讨论】:

          猜你喜欢
          • 2017-11-27
          • 2023-03-23
          • 2012-08-28
          • 1970-01-01
          • 1970-01-01
          • 2018-11-24
          • 2021-07-24
          • 2015-04-25
          • 2019-03-14
          相关资源
          最近更新 更多