1

这是一个python模块。foosys.path.

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

我还没有什么特别的事情发生。如果我想从模块中实例化Derivedderived,我可以很容易地做到这一点:

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

但是,我只想导入bar模块并调用bar.Derived(),因为我计划在许多不同的模块中包含许多类,并且我不想处理所有这些触手可及的导入路径。我的理解是,我可以简单地将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导致derived.py之前执行的 import 语句bar已完全加载,因此它无法导入bar包含其自己的基类的模块(也 from )。我来自 C++ 世界,超嵌套的命名空间不是完整的,简单的前向声明可以解决这个问题,但我被引导相信我正在寻找的东西是可能的,至少是一个在某种程度上可以接受的 Pythonic 解决方案。我究竟做错了什么?使子模块中的类在父模块的命名空间中可用的正确方法是什么?

4

2 回答 2

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在您的模块中。)

于 2012-06-06T21:22:35.703 回答
1

在 derived.py 中,使用这个:

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

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

相反,使用:

from . import base # 

(或者)

from foo.bar import base

代替:

import foo.bar.base as base

这将解决您的两个错误(因为它们来自同一个问题)。您的导入不起作用,因为basefoo.bar.base 模块中没有函数或类。

于 2012-06-06T21:42:00.833 回答