Python如何跟踪使用egg安装的模块?

12 投票
2 回答
8835 浏览
提问于 2025-04-16 07:46

如果我在 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 个回答

3

当你运行 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 文件夹里。

19

如果你使用 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 的原因。

撰写回答