__init__.py 中的导入和“import as”语句

2025-03-21 09:06:00
admin
原创
40
摘要:问题描述:我在包的模块中导入__init__.py和使用绝对导入时遇到了问题。import as我的项目有一个子包,在其中__init__.py我使用语句将模块中的一个类“提升”到子包级别from import as。该模块使用绝对导入从该子包导入其他模块。我收到此错误AttributeError: 'mod...

问题描述:

我在包的模块中导入__init__.py和使用绝对导入时遇到了问题。import as

我的项目有一个子包,在其中__init__.py我使用语句将模块中的一个类“提升”到子包级别from import as。该模块使用绝对导入从该子包导入其他模块。我收到此错误AttributeError: 'module' object has no attribute 'subpkg'

例子

结构

pkg/
├── __init__.py
├── subpkg
│   ├── __init__.py
│   ├── one.py
│   └── two_longname.py
└── tst.py

pkg/ init.py**空的。

pkg/subpkg/初始化.py

from pkg.subpkg.one import One

pkg/subpkg/one.py

import pkg.subpkg.two_longname as two

class One(two.Two):
    pass

pkg/subpkg/two_longname.py

class Two:
    pass

pkg/tst.py

from pkg.subpkg import One

print(One)

输出

$ python3.4 -m pkg.tst
Traceback (most recent call last):
  File "/usr/lib/python3.4/runpy.py", line 170, in _run_module_as_main
    "__main__", mod_spec)
  File "/usr/lib/python3.4/runpy.py", line 85, in _run_code
    exec(code, run_globals)
  File "/home/and/dev/test/python/imptest2/pkg/tst.py", line 1, in <module>
    from pkg.subpkg import One
  File "/home/and/dev/test/python/imptest2/pkg/subpkg/__init__.py", line 1, in <module>
    from pkg.subpkg.one import One
  File "/home/and/dev/test/python/imptest2/pkg/subpkg/one.py", line 1, in <module>
    import pkg.subpkg.two_longname as two
AttributeError: 'module' object has no attribute 'subpkg'

解决方法

有一些变化可以使其发挥作用:

  1. 清空pkg/subpkg/__init__.py并直接从 导入pkg.subpkg.one

我不认为这是一个选项,因为据我所知,“提升”东西到包级别是可以的。以下是一篇文章的引文:

您要做的一件常见事情__init__.py是将选定的类、函数等导入到包级别,以便可以方便地从包中导入它们。

  1. 更改import as为:from importone.py

 from pkg.subpkg import two_longname

 class One(two_longname.Two):
     pass

这里唯一的缺点是我无法为模块创建一个简短的别名。这个想法是从@begueradj 的回答中得到的。

也可以使用相对导入来one.py修复此问题。但我认为这只是解决方法 #2 的变体。

问题

  1. 有人能解释一下这里到底发生了什么吗?为什么导入__init__.py和使用的组合import as会导致这样的问题?

  2. 还有其他更好的解决方法吗?


原始示例

这是我原来的例子。它不太现实,但我不会删除它,所以@begueradj 的回答仍然有意义。

pkg/ init.py**空的。

pkg/subpkg/初始化.py

from pkg.subpkg.one import ONE

pkg/subpkg/one.py

import pkg.subpkg.two
ONE = pkg.subpkg.two.TWO

pkg/subpkg/two.py

TWO = 2

pkg/tst.py

from pkg.subpkg import ONE

输出

$ python3.4 -m pkg.tst
Traceback (most recent call last):
  File "/usr/lib/python3.4/runpy.py", line 170, in _run_module_as_main
    "__main__", mod_spec)
  File "/usr/lib/python3.4/runpy.py", line 85, in _run_code
    exec(code, run_globals)
  File "/home/and/dev/test/python/imptest/pkg/tst.py", line 1, in <module>
    from pkg.subpkg import ONE
  File "/home/and/dev/test/python/imptest/pkg/subpkg/__init__.py", line 2, in <module>
    from pkg.subpkg.one import ONE
  File "/home/and/dev/test/python/imptest/pkg/subpkg/one.py", line 6, in <module>
    ONE = pkg.subpkg.two.TWO
AttributeError: 'module' object has no attribute 'subpkg'

最初我在one.py中有这个:

import pkg.subpkg.two as two
ONE = two.TWO

在这种情况下,我在导入时会出现错误(就像在我原来的项目中使用的那样import as)。


解决方案 1:

您错误地认为不能使用 别名from ... import,因为from ... import ... asPython 2.0 之后就有了 别名。 这import ... as是一种晦涩难懂的语法,很多人都不知道,但您在代码中却不小心用到了它。

PEP 0221声称以下 2 点“实际上”是相同的:

  1. import foo.bar.bazaar as baz

  2. from foo.bar import bazaar as baz

您遇到的极端情况表明,在Python 3.6.x 及以下版本中,该陈述并不完全正确,即如果所需模块已存在于 中sys.modules但尚未初始化。除了位于 中之外,import ... as还要求将模块作为属性foo.bar注入到 命名空间 中,而 则在 中查找。foo`barsys.modulesfrom ... import ... asfoo.barsys.modules`

(还请注意,import foo.bar仅确保模块foo.barsys.modules并且可以访问foo.bar,但可能尚未完全初始化。)

按照如下方式更改代码对我来说很有效:

# import pkg.subpkg.two_longname as two
from pkg.subpkg import two_longname as two

并且代码在 Python 2 和 Python 3 上都能完美运行。

此外,由于同样的原因,one.py您也不能执行。from pkg import subpkg


为了进一步演示此错误,请one.py按上述方法修复您的代码,并在中添加以下代码tst.py

import pkg
import pkg.subpkg.two_longname as two

del pkg.subpkg

from pkg.subpkg import two_longname as two
import pkg.subpkg.two_longname as two

只有最后一行崩溃,因为from ... import查询sys.modulesforpkg.subpkg并在那里找到它,而import ... as查询sys.modulesforpkg并尝试在模块subpkg中找到属性pkg。由于我们刚刚删除了该属性,因此最后一行失败AttributeError: 'module' object has no attribute 'subpkg'


由于import foo.bar as baz语法有点晦涩并增加了更多极端情况,而且我很少见到它被使用,因此我建议完全避免使用它并倾向于使用它from .. import ... as

解决方案 2:

正如接受的答案所述,这是 Python 行为的一个问题。

我已经提交了一个错误:http://bugs.python.org/issue30024

Serhiy Storchaka 的修复已合并并预计在 Python 3.7 中发布

解决方案 3:

以下是关于正在发生之事的一个理论。

当您使用as保留字时,例如:

import pkg.subpkg.two_longname as two

Python 必须完全初始化并解决与有关的所有依赖关系pkg.subpkg。但有一个问题,要完全加载,subpkg您还需要完全加载one.py,对吗?同时two_longname.py使用as关键字导入...您能在这里看到递归吗?这就是为什么在执行时:

import pkg.subpkg.two_longname as two

您收到一条错误消息,声称subpkg不存在。

要进行测试,请转到 one.py 并将其更改为以下内容:

#import pkg.subpkg.two_longname as two
from pkg.subpkg import two_longname

#class One(two.Two):
class One(two_longname.Two):
    pass

我想这都是为了性能,Python 会尽可能地部分加载模块。关键字as是例外之一。我不知道是否还有其他例外,但了解它们会很有趣。

解决方案 4:

关于调用模块的方式的项目结构必须是这样的:

pkg/
├── __init__.py
├── subpkg
│   ├── __init__.py
│   ├── one.py
│   └── two.py
tst.py

像这样定义你的two.py :

class TWO:
    def functionTwo(self):
        print("2")

像这样定义你的one.py :

from pkg.subpkg import two
class ONE:
    def functionOne(self):
        print("1")

        self.T=two.TWO()
        print("Calling TWO from ONE: ")
        self.T.functionTwo()

像这样定义你的test.py

from pkg.subpkg import one
class TEST:
    def functionTest(self):
        O=one.ONE()
        O.functionOne()
if __name__=='__main__':
    T=TEST()
    T.functionTest()

当你执行时,你会得到这个:

1
Calling  TWO from  ONE:
2

希望这有帮助。

相关推荐
  政府信创国产化的10大政策解读一、信创国产化的背景与意义信创国产化,即信息技术应用创新国产化,是当前中国信息技术领域的一个重要发展方向。其核心在于通过自主研发和创新,实现信息技术应用的自主可控,减少对外部技术的依赖,并规避潜在的技术制裁和风险。随着全球信息技术竞争的加剧,以及某些国家对中国在科技领域的打压,信创国产化显...
工程项目管理   2482  
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   1533  
  PLM(产品生命周期管理)项目对于企业优化产品研发流程、提升产品质量以及增强市场竞争力具有至关重要的意义。然而,在项目推进过程中,范围蔓延是一个常见且棘手的问题,它可能导致项目进度延迟、成本超支以及质量下降等一系列不良后果。因此,有效避免PLM项目范围蔓延成为项目成功的关键因素之一。以下将详细阐述三大管控策略,助力企业...
plm系统   0  
  PLM(产品生命周期管理)项目管理在企业产品研发与管理过程中扮演着至关重要的角色。随着市场竞争的加剧和产品复杂度的提升,PLM项目面临着诸多风险。准确量化风险优先级并采取有效措施应对,是确保项目成功的关键。五维评估矩阵作为一种有效的风险评估工具,能帮助项目管理者全面、系统地评估风险,为决策提供有力支持。五维评估矩阵概述...
免费plm软件   0  
  引言PLM(产品生命周期管理)开发流程对于企业产品的全生命周期管控至关重要。它涵盖了从产品概念设计到退役的各个阶段,直接影响着产品质量、开发周期以及企业的市场竞争力。在当今快速发展的科技环境下,客户对产品质量的要求日益提高,市场竞争也愈发激烈,这就使得优化PLM开发流程成为企业的必然选择。缺陷管理工具和六西格玛方法作为...
plm产品全生命周期管理   0  
热门文章
项目管理软件有哪些?
曾咪二维码

扫码咨询,免费领取项目管理大礼包!

云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用