【发布时间】:2014-10-02 16:41:46
【问题描述】:
PEP 302 -- New Import Hooks 指定了挂钩 Python 导入机制的方法。其中之一是创建一个模块查找器/加载器并将其添加到sys.meta_path。
我试图创建一个能够重新路由子包导入的模块查找器。所以假设我写了import mypackage.sub,它实际上应该导入模块mypackage_sub。
mypackage.sub => mypackage_sub
mypackage.sub.another => mypackage_sub.another
mypackage.sub.another.yikes => mypackage_sub.another.yikes
我尝试实现这样的模块查找器没有成功。目前,我将 finder 类安装在 Python 主文件中,但我的目标是将其安装在根包 mypackage 中。
发现者会收到带有'mypackage' 的.find_module(fullname, path) 的呼叫,但绝不会带有'mypackage.sub' 的呼叫。因此,我只收到以下代码的以下错误。
Traceback (most recent call last):
File "test.py", line 63, in <module>
import mypackage.sub
ImportError: No module named sub
import sys
sys.meta_path.append(_ExtensionFinder('mypackage'))
import mypackage.sub
这是_ExtensionFinder 类的代码。我很欣赏任何允许我将这个_ExtensionFinder 类放入根模块mypackage 的解决方案。
class _ExtensionFinder(object):
"""
This class implements finding extension modules being imported by
a prefix. The dots in the prefix are converted to underscores and
will then be imported.
.. seealso:: PEP 302 -- New Import Hooks
"""
def __init__(self, prefix):
super(_ExtensionFinder, self).__init__()
self.prefix = prefix
def _transform_name(self, fullname):
if self.prefix == fullname:
return fullname
elif fullname.startswith(self.prefix + '.'):
newpart = fullname[len(self.prefix) + 1:]
newname = self.prefix.replace('.', '_') + '_' + newpart
return newname
return None
def find_module(self, fullname, path=None):
print "> find_module({0!r}, {1!r})".format(fullname, path)
newname = self._transform_name(fullname)
if newname:
return self
def load_module(self, fullname):
print "> load_module({0!r})".format(fullname)
# If there is an existing module object named 'fullname'
# in sys.modules, the loader must use that existing module.
if fullname in sys.modules:
return sys.modules[fullname]
newname = self._transform_name(fullname)
if newname in sys.modules:
sys.modules[fullname] = sys.modules[newname]
return sys.modules[newname]
# Find and load the module.
data = imp.find_module(newname)
mod = imp.load_module(newname, *data)
# The __loader__ attribute must be set to the loader object.
mod.__loader__ = self
# The returned module must have a __name__, __file__
# and __package__ attribute.
assert all(hasattr(mod, n) for n in ['__name__', '__file__', '__package__'])
return mod
编辑:我发现描述我想要实现的目标的正确词是“命名空间包”
【问题讨论】:
-
你可以在
mypackage.py(或__init__.py):import mypackage_sub as sub,如果这就是你所需要的。 -
@matsjoyce 应该可以动态添加子包,根本不用碰
mypackage.py:) -
我刚刚发现
pkgutil.extend_path()看起来已经非常有用了,不幸的是,这需要将每个单独的命名空间包保存在sys.path的不同目录中,这也不应该是必需的。 -
您希望插入/元路径修改发生在哪里?在
__main__.py?还是mypackage_sub? -
@matsjoyce
mypackage应该修改元路径,以便可以直接导入任何子包而无需进一步麻烦(因为mypackage将在尝试导入mypackage.sub之前导入)
标签: python-2.7 python-2.x import-hooks