我在__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'
有些变化使其有效:
清空pkg/subpkg/__init__.py
并直接从pkg.subpkg.one
导入。
我不认为这是一种选择,因为AFAIK&#34;解除&#34;包级别的东西是好的。以下是an article的引用:
__init__.py
中常见的一件事就是导入所选内容 类,函数等进入包级别,以便它们可以 从包装中方便地进口。
在import as
中将from import
更改为one.py
:
from pkg.subpkg import two_longname
class One(two_longname.Two):
pass
这里唯一的问题是我无法为模块创建短别名。我从@ begueradj的回答中得到了这个想法。
也可以在one.py
中使用相对导入来解决问题。但我认为这只是解决方法#2的变种。
有人能解释一下这里到底发生了什么吗?为什么__init__.py
中的导入组合和import as
的使用会导致此类问题?
有没有更好的解决方法?
这是我原来的例子。这不太现实,但我没有删除它,所以@ 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
的原始项目中一样)。
答案 0 :(得分:14)
你错误地认为一个人不能拥有from ... import
的别名,因为from ... import ... as
自Python 2.0以来一直存在。 import ... as
是一个不为人知的晦涩语法,但是你在代码中偶然使用它。
PEP 0221声称以下2个“有效”相同:
import foo.bar.bazaar as baz
from foo.bar import bazaar as baz
声明并不完全正确,正如您遇到的极端情况所证明的那样,即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 ... as
为sys.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
希望这有帮助。