【问题标题】:How do I make classes from a submodule available in a parent module's namespace?如何使子模块中的类在父模块的命名空间中可用?
【发布时间】:2012-06-07 23:44:25
【问题描述】:

这是一个 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)

我还没有什么花哨的事情。如果我想从 derived 模块实例化 Derived 类,我可以很容易地做到这一点:

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.pybar 完全加载之前执行,因此它无法导入模块(也来自bar)它包含自己的基类。我来自 C++ 世界,超嵌套的命名空间不是完整的,简单的前向声明可以解决这个问题,但我被引导相信我正在寻找的东西是可能的,至少是一个有点可接受的 Pythonic 解决方案。我究竟做错了什么?使子模块中的类在父模块的命名空间中可用的正确方法是什么?

【问题讨论】:

    标签: python import module namespaces package


    【解决方案1】:

    如果您使用的是 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。)

    【讨论】:

      【解决方案2】:

      在 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 函数或类。

      【讨论】:

      • 此时不推荐使用隐式相对导入,所以我会说最好不要使用它们,除非你必须这样做(即你正在使用早于 2.5 的 Python 版本)。
      • @JAB: basederived 在同一目录中。您是说import base(在同一目录中导入模块)已弃用??
      • “在 Python 2.6 中,任何导致包内导入的 import 语句都会引发 DeprecationWarning(这也适用于无法使用相对导入语法的 from <> import)。”我没有在这台计算机上设置 Python 2.6 的副本来测试它,但我敢打赌它会这样做。另请参阅python.org/dev/peps/pep-0328/#rationale-for-absolute-imports
      • 呃,awforsythe 试图使用import foo.bar.base as base,而不是from foo.bar.base import base
      • @JAB:我已经仔细阅读(和其他来源),我可以看到只是一个原始的import base 不是正确的做法。感谢您的启发!... +1 ...它确实可以工作...并且也没有任何弃用警告(在 Python 2.7 上)。我不太确定为什么,因为它不在我的 sys.path 上。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-07-14
      • 2016-04-27
      • 2012-01-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多