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

12
如果我有一个模块fooLib/site-packages中,我只需要导入import foo,就可以使用它。然而,当我从egg中安装东西时,我会得到类似于blah-4.0.1-py2.7-win32.egg的文件夹,其中包含模块内容,但仍然只需要执行import foo,不需要做更复杂的事情。Python是如何跟踪egg的呢?它不仅仅是目录名匹配,如果我将该文件夹放入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,我该怎么使它工作呢?


Python的源代码完全开放给你。你可以轻松地阅读import语句的实现。正如他们所说:“使用源代码,卢克。” - S.Lott
16
@S.Lott:任何问题都可以通过不同程度的“自己动手”来回答,这并不是这个网站的目的。这也更加高效。我不必花费一个小时查看源代码,浪费时间和精力,让我感到不开心。相反,我可以在这里提问,时不时地检查一下,得到我的答案,感到满意,并给别人点赞以释放他们的多巴胺,如果其他人想知道这个问题,这个问题还会在谷歌上出现,等等。 - Claudiu
"浪费一个小时"? 真的吗?"浪费"这个词听起来有些过分了。你会学到很多东西的。而且,文档的这部分似乎很完整。http://docs.python.org/library/modules.html#importing-modules。我很惊讶你没有从文档开始。 - S.Lott
2
S.Lott:eggseasy_install 不是 Python 标准库的一部分,因此仅仅阅读有关导入模块的内容并不能真正回答提问者的问题。 - Ned Deily
2
@S.Lott:没错,浪费是很严重的。我也会学到一些东西。我真正想表达的是比较优势。已经知道这个问题答案的人可以花更少的时间回答我的问题。虽然我没有像他们那样努力,但我仍然通过这种方式学习。我同意这种方式不如自己动手做好,但我认为问这个问题是值得的。当然,在遇到问题时,我们应该先尝试自己解决,而不是立即跳到SO上寻求帮助。 - Claudiu
2个回答

19
如果您使用由setuptools(或其Distribute分支)提供的easy_install脚本以egg的形式安装包,您会发现,默认情况下它会在Python安装的site-packages目录中创建一个名为easy-install.pth的文件。路径配置文件是Python的标准特性:

路径配置文件是一个文件, 其名称具有形式package.pth 并存在于上述四个目录之一; 它的内容是要添加到sys.path的附加项(每行一个)。

easy_install大量使用此Python特性。当您使用easy_install添加或更新分发时,它会修改easy-install.pth以添加egg目录或zip文件。通过这种方式,easy_install维护模块搜索顺序的控制,并确保它安装的egg出现在搜索顺序的前面。以下是一个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的原因。


我从未使用过easy_install脚本,但是当我使用标准方式安装EasyAI(即python -m pip install easyai)时,会自动创建这样的安装(一个.egg文件而不是包中的所有文件)。我已经以这种方式安装了数十个软件包,只有这一个创建了.egg。但这并不影响我。事实上,我想知道如何安装更多的.egg软件包,甚至更好的是,如果我可以将一些已安装的软件包转换为.egg - Apostolos

3
当你运行easy_install时,它会将egg文件复制到site-packages并将该egg文件的路径放在sys.path变量中。(请注意,sys.path不是您的PATH环境变量,它是由PYTHONPATH和其他环境变量构建的。因此,您使用easy_install安装的.egg文件被放置在某个环境变量中,当python解释器启动时,python知道将其添加到sys.path中)。
为了使blah.haha在您的示例中工作,可以运行“easy_install blah-4.0.1-py2.7-win32.egg”,然后您就可以从python中导入haha,或者直接将haha模块放在site-packages中。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接