如何从父模块命名空间中的子模块中创建类?

时间:2012-06-06 21:02:39

标签: python import module namespaces package

这是一个python模块。 foo位于sys.path

foo\
    __init__.py
    bar\
        __init__.py
        base.py
            class Base(object)
        derived.py
            import foo.bar.base as base
            class Derived(base.Base)

我还没有任何幻想。如果我想从derived模块中实例化派生类,我可以轻松地做到这一点:

import foo.bar.derived as derived
print(derived.Derived())

但是,我只想导入bar模块并调用bar.Derived(),因为我打算在很多不同的模块中有很多类,我不想处理所有这些突出的进口路径。我的理解是,我可以简单地将派生导入bar模块的命名空间,方法是修改我的项目:

foo\
    __init__.py
    bar\
        __init__.py
            from foo.bar.derived import Derived
        base.py
            class Base(object)
        derived.py
            import foo.bar.base as base
            class Derived(base.Base)

现在我应该能够做到以下几点:

import foo.bar as bar
print(bar.Derived())

但我得到一个AttributeError抱怨foo模块没有名为bar的子模块:

test.py             (1): import foo.bar
foo\bar\__init__.py (1): from foo.bar.derived import Derived
foo\bar\derived.py  (1): import foo.bar.base as base

AttributeError: 'module' object has no attribute 'bar'

事实上,我原来的测试代码(顶部)也不起作用!一旦我尝试导入foo.bar,我就会收到错误。

我可以从这个错误中发现,__init__.py中的import语句会导致derived.pybar完全加载之前执行,因此无法导入模块(也来自bar),它包含自己的基类。我来自C ++世界,其中超嵌套的命名空间不是完整的,简单的前向声明会否定这个问题,但我一直认为我正在寻找的是可能的,至少是有点可接受的Pythonic解决方案。我究竟做错了什么?从父模块的命名空间中可用的子模块创建类的正确方法是什么?

2 个答案:

答案 0 :(得分:5)

如果您使用的是Python 2.5或更高版本,请尝试使用显式相对导入(http://www.python.org/dev/peps/pep-0328/#guido-s-decision):

test.py             (1): import foo.bar
foo\bar\__init__.py (1): from .derived import Derived
foo\bar\derived.py  (1): from . import base

(请注意,如果您确实使用Python 2.5或2.6,则需要在模块中包含from __future__ import absolute_import。)

答案 1 :(得分:1)

在derived.py中

,使用:

编辑:正如JAB所指出的那样,隐式相对导入已弃用,不建议使用以下内容(尽管它仍在Python 2.7中工作 - 没有弃用)错误!)。

import base#这就是你所需要的 - 它在当前目录中

相反,请使用:

from . import base # 

<强>(或)

from foo.bar import base

代替:

import foo.bar.base as base

这将解决您的错误(因为它们来自同一个问题)。由于foo.bar.base模块中没有base函数或类,导入无效。