Python中"import lib.foo"和"import lib.foo as f"的区别

9

我对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尝试访问lib上的foo属性并引发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'

链接http://google-styleguide.googlecode.com/svn/trunk/pyguide.html?showone=Imports#Imports已经失效 - 重新添加会很好。 - Mr_and_Mrs_D
1个回答

6
当你使用import lib.foo as f时,相当于在字节码级别上执行import lib.foo; f = lib.foo。由于在这种情况下lib还没有将foo设置为属性,所以你会遇到一个属性错误。当Python尝试执行赋值操作时,它的导入过程还没有完成lib.foo的导入,因此尚未在lib上设置该属性。查看Python 3.3源代码中的导入部分,可以看到加载模块和几个语句之后将模块设置为其父级
这就是为什么会有一些循环导入问题。在访问lib.foo之前,你需要让导入lib.foo完成,否则lib上的属性就不存在了。这可能就是你认为你没有直接在代码中使用任何顶级定义的原因,但实际上是通过导入语句间接地使用了。

谢谢您的回答!所以当我导入 lib.foo 时,首先导入的是 lib,然后在导入 lib.foo 时,在 lib 中设置了一个 foo 属性。这就是为什么稍后 lib.foo.something 能够正常工作:它在 lib 包上找到了 foo 属性 —— 这也解释了为什么 import lib.foolib 放入本地命名空间中。 - Martin Geisler

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接