导入__init__.py和`import as`语句

时间:2014-07-17 15:15:06

标签: python python-3.x

我在__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 / __初始化__吡啶

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导入。

    我不认为这是一种选择,因为AFAIK&#34;解除&#34;包级别的东西是好的。以下是an article的引用:

      

    __init__.py中常见的一件事就是导入所选内容   类,函数等进入包级别,以便它们可以   从包装中方便地进口。

  2. import as中将from import更改为one.py

    from pkg.subpkg import two_longname
    
    class One(two_longname.Two):
        pass
    

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

  3. 也可以在one.py中使用相对导入来解决问题。但我认为这只是解决方法#2的变种。

    问题

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

    2. 有没有更好的解决方法?


    3. 原始示例

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

      pkg / __ init __。py 为空。

      PKG / subpkg / __初始化__吡啶

      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的原始项目中一样)。

4 个答案:

答案 0 :(得分:14)

你错误地认为一个人不能拥有from ... import的别名,因为from ... import ... as自Python 2.0以来一直存在。 import ... as是一个不为人知的晦涩语法,但是你在代码中偶然使用它。

PEP 0221声称以下2个“有效”相同:

  1. import foo.bar.bazaar as baz
  2. from foo.bar import bazaar as baz
  3. 声明并不完全正确,正如您遇到的极端情况所证明的那样,即sys.modules中是否已存在所需的模块但尚未初始化。 import ... as要求模块foo.bar作为属性foo注入bar名称空间,除了sys.modules之外,from ... import ... as foo.bar }在sys.modules中查找import foo.bar

    (请注意,foo.bar仅确保模块sys.modules位于foo.bar并且可以# import pkg.subpkg.two_longname as two from pkg.subpkg import two_longname as two 访问,但可能尚未完全初始化。)

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

    one.py

    代码在Python 2和Python 3上运行完美。

    此外,在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.modules查询pkg.subpkg的{​​{1}}并在那里找到它,而import ... assys.modules咨询pkg并尝试在subpkg模块中查找pkg作为属性。由于我们刚刚删除了该属性,因此最后一行失败了AttributeError: 'module' object has no attribute 'subpkg'


    由于import foo.bar as baz语法有点模糊,并且添加了更多的极端情况,而且我很少看到它被使用过,我建议完全避免使用它并偏向from .. import ... as

答案 1 :(得分: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关键字是例外情况之一。我不知道是否还有其他人,但了解它们会很有趣。

答案 2 :(得分:3)

正如公认的回答所说,这是Python行为的一个问题。

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

Serhiy Storchaka的修复程序在Python 3.7中被合并并预期

答案 3 :(得分:2)

关于调用模块的方式的项目结构必须如下:

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

希望这有帮助。

相关问题