我对Python中循环导入的处理方式感到困惑。我试图提炼一个最小的问题,我不认为这个确切的变体之前被问过。基本上,我看到了
之间的区别import lib.foo
和
import lib.foo as f
当lib.foo
和lib.bar
之间存在循环依赖关系时。我原本以为两者都是一样的:(可能是半初始化的)模块可以在sys.modules
中找到并放入本地命名空间。 (从测试中我注意到import lib.foo
确实将lib
放入了本地命名空间 - 好吧,不管怎么说,我会做lib.foo.something
语法。)
但是,如果lib.foo
已经在sys.modules
中,那么import lib.foo as f
会尝试访问foo
作为lib
上的属性并引发AttributeError。为什么行为(看似)依赖于sys.modules
中的存在?
此外,这种行为记录在哪里?我不认为Python import
statement reference解释了这种行为,或者至少我无法提取它: - )
总而言之,我正在尝试更改代码库以使用导入模块的oft recommended样式,而不是模块中的符号:
from project.package import moduleA
from project.package import moduleB
但是当两个模块之间存在循环导入时,这会失败。只要两个模块中的顶级定义不相互依赖(例如,moduleB
中没有基类moduleA
中的子类),我原本期望它能够工作。
测试脚本:
#!/bin/sh
rm -r lib; mkdir lib
touch lib/__init__.py
cat > lib/foo.py <<EOF
# lib.foo module
print '{ foo'
#import lib.bar # works
import lib.bar as b # also works
#from lib import bar # also works
print 'foo }'
EOF
cat > lib/bar.py <<EOF
# lib.bar module
print '{ bar'
#import lib.foo # works
import lib.foo as f # AttributeError: 'module' object has no attribute 'foo'
#from lib import foo # ImportError: cannot import name foo
print 'bar }'
EOF
python -c 'import lib.foo'
答案 0 :(得分:6)
当你说import lib.foo as f
时,你告诉Python要做的是在字节码级别上等同于import lib.foo; f = lib.foo
。您在被询问的问题中最终会出现AttributeError,因为在这种情况下lib
尚未将foo
设置为属性。 Python在尝试执行赋值时尚未完成lib.foo
的导入,因此尚未在lib
上设置属性;查看用于导入的Python 3.3源代码,您可以在module is loaded处看到module is set on its parent与情侣语句的距离更远。
这是您最终遇到一些循环导入问题的地方。在尝试访问lib.foo
之前,您需要完成lib.foo
的导入,否则lib
上的属性根本不存在,无法访问字节码。这可能就是为什么您认为您没有直接在代码中使用任何顶级定义,但实际上您是通过导入语句。