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

时间:2023-01-23 21:56:34

I'm puzzled by how circular imports are handled in Python. I've tried to distill a minimal question and I don't think this exact variant was asked before. Basically, I'm seeing a difference between

我对Python中如何处理循环导入感到困惑。我试着提炼出一个最小的问题,我不认为这个确切的变体之前被问过。基本上,我看到了两者之间的区别

import lib.foo

and

import lib.foo as f

when I have a circular dependency between lib.foo and lib.bar. I had expected that both would work the same: the (possibly half-initialized) module would be found in sys.modules and put into the local namespace. (From testing I noticed that import lib.foo really puts lib into the local namespace — okay, with that syntax I'll do lib.foo.something anyway.)

当我有一个循环依赖在lib。foo和lib。bar之间。我原以为两者都可以工作:在sys中可以找到(可能是半初始化的)模块。将模块放入本地命名空间。(通过测试,我注意到import lib.foo实际上将lib放入了本地名称空间中——好的,使用这个语法,我将使用lib.foo。无论如何。)

However, if lib.foo is already in sys.modules, then import lib.foo as f tries to access foo as an attribute on lib and raises AttributeError. Why does the behavior (seemingly) depend on the presence in sys.modules?

但是,如果lib.foo已经在sys中了。模块,然后导入lib.foo,因为f试图以lib的属性访问foo,并引发AttributeError。为什么行为(似乎)依赖于sys.modules中的存在?

Also, where is this behavior documented? I don't feel that the Python import statement reference explains this behavior, or at least I couldn't extract it :-)

还有,这种行为记录在哪里?我不认为Python导入语句引用可以解释这种行为,或者至少我不能提取它:-)

All in all I'm trying to change a code base to use the oft recommended style where you import modules, not symbols in the modules:

总的来说,我正在尝试改变一个代码库,以使用oft推荐的样式,在其中导入模块,而不是模块中的符号:

from project.package import moduleA
from project.package import moduleB

But that fails when there are circular imports between the two modules. I had expected it to work as long as the top-level definitions in the two modules don't depend on each other (e.g., no subclass in moduleB with a base class in moduleA).

但当两个模块之间有循环导入时,就会失败。只要两个模块中的*定义不相互依赖(例如,moduleB中没有子类,moduleA中有基类),我就期望它能正常工作。

Test script:

测试脚本:

#!/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 个解决方案

#1


6  

When you say import lib.foo as f what you are telling Python to do is the equivalent of import lib.foo; f = lib.foo at the bytecode level. You end up with an AttributeError in the issue being asked because lib in this case doesn't have foo set yet as an attribute. Python hasn't completed its import of lib.foo when it tries to do the assignment and thus has not set the attribute yet on lib; look at the Python 3.3 source for import where you can see where a module is loaded vs. couple statements farther down where a module is set on its parent.

当你说把lib.foo作为f导入时你告诉Python要做的是相当于导入lib.foo;f = lib.foo在字节码级别。在被询问的问题中,您最终会得到一个AttributeError,因为在本例中,lib还没有foo集作为属性。当Python尝试执行赋值时,它还没有完成lib.foo的导入,因此还没有在lib上设置属性;请查看Python 3.3源代码以获取导入,在那里您可以看到模块被加载的位置,以及模块在父模块上的位置。

This is where you end up with some circular import issues. You need to let the import for lib.foo complete before you try to access lib.foo, else the attribute on lib simply won't exist yet for the bytecode to access. This might be why you think you are not using any top-level definitions directly in your code but in actuality you are through your import statements.

这将导致一些循环导入问题。在尝试访问lib.foo之前,您需要让lib.foo的导入完成,否则lib上的属性将不会存在,以便字节码访问。这可能是为什么您认为您没有在代码中直接使用任何*定义,但实际上您是通过导入语句。

#1


6  

When you say import lib.foo as f what you are telling Python to do is the equivalent of import lib.foo; f = lib.foo at the bytecode level. You end up with an AttributeError in the issue being asked because lib in this case doesn't have foo set yet as an attribute. Python hasn't completed its import of lib.foo when it tries to do the assignment and thus has not set the attribute yet on lib; look at the Python 3.3 source for import where you can see where a module is loaded vs. couple statements farther down where a module is set on its parent.

当你说把lib.foo作为f导入时你告诉Python要做的是相当于导入lib.foo;f = lib.foo在字节码级别。在被询问的问题中,您最终会得到一个AttributeError,因为在本例中,lib还没有foo集作为属性。当Python尝试执行赋值时,它还没有完成lib.foo的导入,因此还没有在lib上设置属性;请查看Python 3.3源代码以获取导入,在那里您可以看到模块被加载的位置,以及模块在父模块上的位置。

This is where you end up with some circular import issues. You need to let the import for lib.foo complete before you try to access lib.foo, else the attribute on lib simply won't exist yet for the bytecode to access. This might be why you think you are not using any top-level definitions directly in your code but in actuality you are through your import statements.

这将导致一些循环导入问题。在尝试访问lib.foo之前,您需要让lib.foo的导入完成,否则lib上的属性将不会存在,以便字节码访问。这可能是为什么您认为您没有在代码中直接使用任何*定义,但实际上您是通过导入语句。