没有__init__的Python包

14 投票
3 回答
3418 浏览
提问于 2025-04-17 06:13

我用 pip install 安装了一个叫 flufl.enum 的Python包,发现它居然可以正常工作,尽管缺少了像普通Python包那样的 flufl/__init__.py 模块。这真是太奇怪了:

>>> import flufl
>>> flufl
<module 'flufl' (built-in)>

我尝试自己复现这个情况,创建了 foo/bar/__init__.py,但没有 foo/__init__.py,结果(果然) import foo 失败了。那 flufl 是怎么做到的呢?

3 个回答

0

flufl 只是一个命名空间包,它在 egg 的 namespace_packages.txt 文件中被声明。

如果你查看它的源代码树,你会发现里面确实有 flufl/__init__.py 这个文件,但在作为 egg 分发的时候,由于 setuptools 的一些特殊处理,这个文件似乎并不是必须的。

0

我不太明白这个。

ls /Users/sbo/lib/python2.7/site-packages/flufl.enum-3.2-py2.7.egg/flufl/
__init__.py   __init__.pyc  enum/

你是不是把 flufl.enum 和 Python 一起编译了?这是它成为内置模块的唯一方法。

顺便说一下,我确实看过一个 PEP(Python 的提案),里面提到过包可以跳过初始化,但我不记得这个提案是被批准了、拒绝了,还是正在审查中。

19

这个神奇的事情发生在一个叫做 flufl.enum-3.2-py2.7-nspkg.pth 的文件里,这个文件是通过 "pip install" 命令放到 site-packages 里的:

import sys,new,os
p = os.path.join(sys._getframe(1).f_locals['sitedir'], *('flufl',))
ie = os.path.exists(os.path.join(p,'__init__.py'))
m = not ie and sys.modules.setdefault('flufl',new.module('flufl'))
mp = (m or []) and m.__dict__.setdefault('__path__',[])
(p not in mp) and mp.append(p)

pth 文件在程序启动时会被读取。特别是,这个文件会创建一个新的模块,叫做 "flufl",并把它放进 sys.modules 里。这也解释了为什么你会看到它被标记为 "内置":

>>> import new
>>> new.module('foo')
<module 'foo' (built-in)>

撰写回答