9

我对 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

此外,这种行为记录在哪里?我不觉得Pythonimport语句参考解释了这种行为,或者至少我无法提取它:-)

总而言之,我正在尝试更改代码库以使用导入模块时经常推荐的样式,而不是模块中的符号:

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'
4

1 回答 1

6

当你说import lib.foo as f你告诉 Python 做什么时,相当于import lib.foo; f = lib.foo在字节码级别。您最终会在被询问的问题中遇到 AttributeError ,因为lib在这种情况下foo尚未将其设置为属性。Python 尚未完成其lib.foo何时尝试执行分配的导入,因此尚未将属性设置为 on lib;查看用于导入的 Python 3.3 源代码,您可以在其中看到模块的加载位置与在其 parent 上设置模块的更下方的几个语句。

这是您最终遇到一些循环导入问题的地方。lib.foo在尝试访问之前,您需要让导入完成lib.foo,否则属性 onlib根本不存在,字节码无法访问。这可能就是为什么您认为您没有直接在代码中使用任何顶级定义,但实际上您是通过 import 语句。

于 2012-10-11T15:17:45.533 回答