繁体   English   中英

如何在Python中预先添加sys.path的路径?

[英]How to prepend a path to sys.path in Python?

问题描述:

使用pip,我升级到最新版本的请求 (版本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.pth被覆盖每次easy-install使用,我的变化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 )。

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

PYTHONPATHs来自Ubuntu的路径

Stack Overflow的另一个答案对我不起作用。 我的PYTHONPATH路径位于easy-install.pth的路径之后,它使用我在“Unsatisfactory solution 3”中提到的相同代码来添加其路径。

先感谢您!

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

>>> 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']
>>>

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

你不应该捣乱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安装正确的软件包。

回答直接问题

您可以在site-packages目录中创建名为sitecustomize目录。 我们会变成这个sitecustomize描述模块这里 (Python的2 这里 )。 特别:

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

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的答案在这里是正确的 - 似乎你正在使用pip从一个安装python可执行文件到另一个。 通过弄乱路径掩盖这一点可能会很快变得非常混乱。 我肯定会确保你为每次安装python都有一个单独的pip并且你使用它。 这应该保持单独安装的目录结构分开。 否则,您强制一次安装使用来自不同安装目录的软件包。 在技​​术上没问题,但在后勤方面令人困惑。

使用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中安装的内容优先于系统范围的库。

我相信能满足你的需求。

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

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

我会使用sitecustomize执行此sitecustomize ,如site.py文档中所述。 在配置初始sys.path之后导入此文件,您可以根据需要使用它以任意方式更改sys.path

我已经将它用作系统管理员来包含自定义发布位置,它可以很好地完成工作。

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

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

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

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

从事物的声音来看,Ubuntu正在使用这里记录的包路径配置文件来设置它安装的任何包。

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

我认为这给了你三个我可以看到的选择:

  1. 按照@ bufh的回答使用virtualenv --system-site-packages。
  2. 使用pip user installs在标准站点包之前的路径中设置所需的包。
  3. 使用sitecustomize重新编写sys.path(例如,将本地目录放在第一位)。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM