我在 __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/init.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'
解决方法
有使其工作的变化:
清空
pkg/subpkg/__init__.py
并直接从pkg.subpkg.one
导入。我不认为这是一个选项,因为 AFAIK 将东西“提升”到包级别是可以的。这是引自 an article :
One common thing to do in your
__init__.py
is to import selected Classes, functions, etc into the package level so they can be conveniently imported from the package.在
one.py
中将import as
更改为from import
: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/init.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
一样)。
最佳答案
您错误地认为不能使用 from ... import
别名,因为 from ... import ... as
自 Python 2.0 以来一直存在。 import ... as
是一种鲜为人知的语法,但您在代码中无意中使用了它。
PEP 0221声称以下 2 个“有效地”相同:
将 foo.bar.bazaar 导入为 baz
from foo.bar import bazaar as baz
该声明在 Python 3.6.x 及之前的版本中并不完全正确,您遇到的极端情况证明了这一点,即如果所需的模块已经存在于 sys.modules
但尚未初始化。 import ... as
要求将模块 foo.bar
作为属性 bar
注入(inject)到 foo
命名空间中,除了在 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
而且代码在 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
为 pkg.subpkg
查询 sys.modules
并在那里找到它,而 import ... as
为 pkg
查询 sys.modules
并尝试在pkg
模块。由于我们刚刚删除了该属性,最后一行失败并显示 AttributeError: 'module' object has no attribute 'subpkg'
。
由于 import foo.bar as baz
语法有点晦涩,而且添加了更多极端情况,而且我很少看到它被使用,我建议完全避免使用它并支持 from .. import ... as
.
关于python - 导入 __init__.py 和 'import as' 语句,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57090921/