确实,addsitedir()不处理 zip 文件;但它应该很容易复制行为。
见site.addsitedir()源代码;该代码只是尝试调用os.listdir()路径然后发现.pth文件:
try:
names = os.listdir(sitedir)
except os.error:
return
dotpth = os.extsep + "pth"
names = [name for name in names if name.endswith(dotpth)]
for name in sorted(names):
addpackage(sitedir, name, known_paths)
addpackage()只是在哪里site.addpackage()。您可以将上面names的列表替换为.pthzipfile 中的文件列表。您还必须复制该site.addpackage()行为,该函数期望能够读取.pth文件。
简化后,该函数执行以下操作:
with f:
for n, line in enumerate(f):
if line.startswith("#"):
continue
if line.startswith(("import ", "import\t")):
exec line
continue
line = line.rstrip()
dir, dircase = makepath(sitedir, line)
if not dircase in known_paths and os.path.exists(dir):
sys.path.append(dir)
known_paths.add(dircase)
混合了异常处理。makepath()is site.makepath(),并known_paths确保找到的任何路径只添加一次。
因此,从本质上讲,所有以 by 命名的项目都会.pth添加到您的文件中,sys.path但以 开头的任何内容import都会在那里执行,然后为.pth文件提供一个进入site.py加载阶段的钩子。
基于 - 的包使用该import钩子setuptools来构建命名空间包;这是命名空间中的一个包中的一个zc:
import sys,types,os; p = os.path.join(sys._getframe(1).f_locals['sitedir'], *('zc',)); ie = os.path.exists(os.path.join(p,'__init__.py')); m = not ie and sys.modules.setdefault('zc',types.ModuleType('zc')); mp = (m or []) and m.__dict__.setdefault('__path__',[]); (p not in mp) and mp.append(p)
sys.modules它使用函数中的sitedir局部变量创建一个空模块对象addpackage()。注意os.path.exists()通话;对于压缩鸡蛋,这将失败(不添加空模块对象),因此您可能需要检测命名空间包并为这些包提供您自己的版本。命名空间中的任何包都zc只是确保ModuleType()它关心的父命名空间有一个对象,其__path__属性指向{sitedir}/{packagename}/__init__.py.
另一种选择是将命名空间包合并到一个目录结构中。