Python如何跟踪使用egg安装的模块?
如果我在 Lib/site-packages
里有一个模块 foo
,我只需要用 import foo
就能使用它。但是,当我从 eggs 安装东西时,我得到的文件夹名字像是 blah-4.0.1-py2.7-win32.egg
,里面有模块的内容,但我仍然只需要用 import foo
,不需要做更复杂的事情。Python 是怎么管理这些 eggs 的呢?这可不是简单的文件夹名字匹配,因为如果我把那个文件夹直接放到 Python 的安装目录里,而不通过 dist-utils,它就找不到这个模块。
为了更清楚一点:我刚安装了 zope。文件夹的名字是 "zope.interface-3.3.0-py2.7-win32.egg"。这样用是可以的:
Python 2.7.1 (r271:86832, Nov 27 2010, 18:30:46) [MSC v.1500 32 bit (Intel)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import zope.interface
>>>
我创建了一个 "blah-4.0.1-py2.7-win32.egg" 的文件夹,里面有一个空模块 "haha"(还有 __init__.py
)。这样用就不行:
Python 2.7.1 (r271:86832, Nov 27 2010, 18:30:46) [MSC v.1500 32 bit (Intel)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import blah.haha
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ImportError: No module named blah.haha
>>>
不过这样用是可以的:
Python 2.7.1 (r271:86832, Nov 27 2010, 18:30:46) [MSC v.1500 32 bit (Intel)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> from pkg_resources import require
>>> require("blah>=1.0")
[blah 4.0.1 (c:\python27\lib\site-packages\blah-4.0.1-py2.7-win32.egg)]
>>> import haha
>>>
那么我怎么才能在没有 require
的情况下让它工作呢?
2 个回答
当你运行 easy_install 时,它会把一个叫做 egg 的文件复制到 site-packages 文件夹里,并把这个 egg 的路径添加到你的 sys.path 变量中。需要注意的是,sys.path 和你的 PATH 环境变量是不同的。sys.path 是由 PYTHONPATH 和其他环境变量构成的。所以你用 easy_install 安装的 .egg 文件会放在某个环境变量里,Python 启动时会知道把它加到 sys.path 中。
要让你的例子中的 blah.haha 正常工作,你可以运行 easy_install blah-4.0.1-py2.7-win32.egg
,然后就可以在 Python 中使用 import haha
,或者你也可以直接把 haha 模块放到 site-packages 文件夹里。
如果你使用 setuptools
提供的 easy_install
脚本(或者它的一个分支 Distribute
)来安装软件包,默认情况下,它会在你 Python 安装的 site-packages
目录下创建一个叫 easy-install.pth
的文件。路径配置文件 是 Python 的一个标准功能:
路径配置文件是一个文件,名字的格式是 package.pth,并且存在于上面提到的四个目录中的一个;它的内容是要添加到 sys.path 的额外项目(每行一个)。
easy_install
大量使用了这个 Python 特性。当你用 easy_install
来添加或更新一个软件包时,它会修改 easy-install.pth
文件,添加 egg 目录或 zip 文件。这样,easy_install
就能控制模块搜索的顺序,确保它安装的 eggs 在搜索顺序中优先出现。下面是一个 easy-install.pth
文件的内容示例:
import sys; sys.__plen = len(sys.path)
./appscript-0.21.1-py2.6-macosx-10.5-ppc.egg
./yolk-0.4.1-py2.6.egg
./Elixir-0.7.1-py2.6.egg
./Fabric-0.9.0-py2.6.egg
import sys; new=sys.path[sys.__plen:]; del sys.path[sys.__plen:]; p=getattr(sys,'__egginse
rt',0); sys.path[p:p]=new; sys.__egginsert = p+len(new)
正如你在这里看到的,如果你查看 setuptools
的代码,你会发现它使用了一些技巧来启动自己,然后掩盖自己的痕迹,这可能会让调试 site.py
和解释器启动的问题变得有点 有趣。(这也是一些开发者不太喜欢使用它的原因之一。)
如果你使用 easy_install
的 -m
参数来以 多版本 的方式安装一个软件包,那么它的 easy-install.pth
条目就不会被添加,或者如果已经存在则会被移除。这就是为什么 easy_install
文档 会告诉你在删除已安装的 egg 之前使用 -m
的原因。