Python中“import lib.foo”和“import lib.foo as f”之间的区别

时间:2012-10-11 09:12:23

标签: python module circular-dependency python-import

我对Python中循环导入的处理方式感到困惑。我试图提炼一个最小的问题,我不认为这个确切的变体之前被问过。基本上,我看到了

之间的区别
import lib.foo

import lib.foo as f

lib.foolib.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'

1 个答案:

答案 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上的属性根本不存在,无法访问字节码。这可能就是为什么您认为您没有直接在代码中使用任何顶级定义,但实际上您是通过导入语句。