and*_*and 19 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
Run Code Online (Sandbox Code Playgroud)
pkg/__ init__.py为空.
pkg/subpkg/__ init__.py:
from pkg.subpkg.one import One
Run Code Online (Sandbox Code Playgroud)
pkg/subpkg/one.py:
import pkg.subpkg.two_longname as two
class One(two.Two):
pass
Run Code Online (Sandbox Code Playgroud)
pkg/subpkg/two_longname.py:
class Two:
pass
Run Code Online (Sandbox Code Playgroud)
pkg/tst.py:
from pkg.subpkg import One
print(One)
Run Code Online (Sandbox Code Playgroud)
输出:
$ 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'
Run Code Online (Sandbox Code Playgroud)
有些变化使其有效:
清空pkg/subpkg/__init__.py
并直接导入pkg.subpkg.one
.
我不认为这是一个选项,因为AFAIK"提升"到包级别的东西是可以的.这是一篇文章的引用:
在init .py中要做的一件事是将选定的类,函数等导入到包级别中,以便可以方便地从包中导入它们.
更改__init__.py
到import as
在from import
:
from pkg.subpkg import two_longname
class One(two_longname.Two):
pass
Run Code Online (Sandbox Code Playgroud)
这里唯一的问题是我不能为模块创建一个简短的别名.我从@ begueradj的回答中得到了这个想法.
也可以使用相对导入one.py
来解决问题.但我认为这只是变通方法#2的变种.
有人能解释一下这里到底发生了什么吗?为什么进口one.py
和使用的组合__init__.py
导致了这样的问题?
有没有更好的解决方法?
这是我最初的例子.这不是很现实,但我没有删除它所以@ begueradj的答案仍然有意义.
pkg/__ init__.py为空.
pkg/subpkg/__ init__.py:
from pkg.subpkg.one import ONE
Run Code Online (Sandbox Code Playgroud)
pkg/subpkg/one.py:
import pkg.subpkg.two
ONE = pkg.subpkg.two.TWO
Run Code Online (Sandbox Code Playgroud)
pkg/subpkg/two.py:
TWO = 2
Run Code Online (Sandbox Code Playgroud)
pkg/tst.py:
from pkg.subpkg import ONE
Run Code Online (Sandbox Code Playgroud)
输出:
$ 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'
Run Code Online (Sandbox Code Playgroud)
最初我在one.py中有这个:
import pkg.subpkg.two as two
ONE = two.TWO
Run Code Online (Sandbox Code Playgroud)
在这种情况下,我在导入时遇到错误(就像在我使用的原始项目中一样import as
).
Ant*_*ala 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
Run Code Online (Sandbox Code Playgroud)
代码在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
Run Code Online (Sandbox Code Playgroud)
只有最后一行崩溃,因为from ... import
在咨询sys.modules
了pkg.subpkg
,发现它在那里,而import ... as
咨询sys.modules
的pkg
,并试图找出subpkg
为在属性pkg
模块.由于我们刚刚删除了该属性,因此最后一行失败了AttributeError: 'module' object has no attribute 'subpkg'
.
由于import foo.bar as baz
语法有点模糊,并且添加了更多的极端情况,并且我很少见到它被使用过,我建议完全避免使用它from .. import ... as
.