PYTHONPATH环境变量前的路径中的Eggs
如果我通过 easy_install 安装了一些包,那么这些包的路径会被放在 sys.path
的最前面,优先于 PYTHONPATH
变量中的内容。
举个例子,如果我安装了一个叫 foo 的包,同时在当前目录下也有一个叫 foo 的包,然后我执行以下代码:
PYTHONPATH="." python
>>> import foo
这样的话,程序会使用安装的那个 foo
包,而不是当前目录下的那个。查看 sys.path
的内容可以发现,包的路径确实是放在 PYTHONPATH 之前的。这看起来有点问题。有没有办法改变这种行为呢?
3 个回答
我做了一些类似下面的操作,以便在运行顶层的 Python 可执行文件时,将某个路径添加到系统路径的最前面:
import sys
sys.path = ["<your python path>"] + sys.path
通常,对我来说,"<你的 Python 路径>"
是通过使用 __file__
属性来相对查找一个包含我项目顶层模块的路径。这种做法在生成包时并不推荐使用,不过我似乎并不在意可能带来的后果。也许还有其他替代 __file__
的方法。
可以考虑使用 -S
这个命令行选项来禁止处理 *.pth
文件:
python -c 'import sys; print("\n".join(sys.path))'
python -S -c 'import sys; print("\n".join(sys.path))'
https://docs.python.org/3/library/site.html#site.main
你还可以在使用 site.main()
时加上 -S
,这样可以把 *.pth
文件的处理推迟到运行时,比如说为了捕获原始的 sys.path 以便后续添加:
export PYTHONPATH=$(
PYTHONPATH='' \
python -c 'import sys; \
sys.path.extend(sys.argv[1:]); old=list(sys.path); \
import site; site.main(); \
[ old.append(p) for p in sys.path if p not in old ]; \
sys.path=old; \
print ":".join(sys.path)' \
$EXTRA_PATH $ANOTHER_PATH)
python -S ... # using explicit PYTHONPATH
- 从一个空的
PYTHONPATH
开始 - 用 extend 明确地将新的路径添加到 sys.path
- 导入 site 模块并调用
site.main()
- 将新的路径添加到旧路径中,然后把它安装到 sys.path
- 用 ":" 来打印
PYTHONPATH
- 对于后续的运行,使用
python -S
是比较好的,这样只会使用$PYTHONPATH
- 在设置
PYTHONPATH
时,使用python -S
可能有用也可能没用,这取决于你是否需要在扩展之前先扩展 sys.path
很不幸,这个问题是因为在 setuptools/command/easy_install.py
里有一个硬编码的模板。你可以创建一个修改过的 setuptools 来编辑这个模板,但我没有找到一个干净的方法可以从外部扩展 easy_install。
每次运行 easy_install 时,它都会重新生成一个叫 easy_install.pth
的文件。这里有一个简单的脚本,你可以在 easy_install 之后运行,用来去掉 easy_install.pth
文件的头部和尾部。你可以创建一个包装的 shell 脚本,让它在 easy_install
之后立即运行:
#!/usr/bin/env python
import sys
path = sys.argv[1]
lines = open(path, 'rb').readlines()
if lines and 'import sys' in lines[0]:
open(path, 'wb').write(''.join(lines[1:-1]) + '\n')
示例:
% easy_install gdata
% PYTHONPATH=xyz python -c 'import sys; print sys.path[:2]'
['', '/Users/pat/virt/lib/python2.6/site-packages/gdata-2.0.14-py2.6.egg']
% ./fix_path ~/virt/lib/python2.6/site-packages/easy_install.pth
% PYTHONPATH=xyz python -c 'import sys; print sys.path[:2]'
['', '/Users/pat/xyz']
为了更清楚,这里是 easy-install.pth
的格式:
import sys; sys.__plen = len(sys.path)
./gdata-2.0.14-py2.6.egg
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)
这两行 import sys
是导致路径开头出现 eggs 的罪魁祸首。我的脚本只是去掉了那些修改 sys.path
的行。