在Python中,当两个模块试图相互导入时会发生什么?更一般地说,如果多个模块试图在一个循环中导入会发生什么?


另见我能做什么关于“ImportError:不能导入名称X”或“AttributeError:…”(很可能是由于循环导入)”?关于可能导致的常见问题,以及如何重写代码以避免此类导入的建议。参见为什么循环导入看起来在调用堆栈中更上一层,但随后在更下一层引发ImportError ?有关问题发生的原因和方式的技术细节。


当前回答

假设您正在运行一个名为request.py的测试python文件 在request.py中,您写入

import request

所以这也很可能是一个循环导入。

解决方案:

只需将测试文件更改为另一个名称,例如aaa.py,而不是request.py。

不要使用其他库已经使用过的名称。

其他回答

这里有个例子让我震惊!

foo.py

import bar

class gX(object):
    g = 10

bar.py

from foo import gX

o = gX()

main.py

import foo
import bar

print "all done"

在命令行:$ python main.py

Traceback (most recent call last):
  File "m.py", line 1, in <module>
    import foo
  File "/home/xolve/foo.py", line 1, in <module>
    import bar
  File "/home/xolve/bar.py", line 1, in <module>
    from foo import gX
ImportError: cannot import name gX

令我惊讶的是,还没有人提到由类型提示引起的循环导入。 如果只有由于类型提示才有循环导入,则可以以干净的方式避免它们。

考虑main.py,它使用了来自另一个文件的异常:

from src.exceptions import SpecificException

class Foo:
    def __init__(self, attrib: int):
        self.attrib = attrib

raise SpecificException(Foo(5))

专用异常类exceptions.py:

from src.main import Foo

class SpecificException(Exception):
    def __init__(self, cause: Foo):
        self.cause = cause

    def __str__(self):
        return f'Expected 3 but got {self.cause.attrib}.'

这将引发ImportError,因为main.py导入了exception.py,反之亦然,通过Foo和SpecificException。

Because Foo is only required in exceptions.py during type checking, we can safely make its import conditional using the TYPE_CHECKING constant from the typing module. The constant is only True during type checking, which allows us to conditionally import Foo and thereby avoid the circular import error. Something to note is that by doing so, Foo is not declared in exceptions.py at runtime, which leads to a NameError. To avoid that, we add from __future__ import annotations which transforms all type annotations in the module to strings.

因此,我们得到以下Python 3.7+的代码:

from __future__ import annotations
from typing import TYPE_CHECKING
if TYPE_CHECKING:  # Only imports the below statements during type checking
   ​from src.main import Foo

class SpecificException(Exception):
   def __init__(self, cause: Foo):  # Foo becomes 'Foo' because of the future import
       ​self.cause = cause

   ​def __str__(self):
       ​return f'Expected 3 but got {self.cause.attrib}.'

在Python 3.6中,future import不存在,所以Foo必须是一个字符串:

from typing import TYPE_CHECKING
if TYPE_CHECKING:  # Only imports the below statements during type checking
   ​from src.main import Foo

class SpecificException(Exception):
   ​def __init__(self, cause: 'Foo'):  # Foo has to be a string
       ​self.cause = cause

   ​def __str__(self):
       ​return f'Expected 3 but got {self.cause.attrib}.'

在Python 3.5及以下版本中,类型提示功能还不存在。 在Python的未来版本中,注解特性可能会成为强制性的,之后就不再需要导入了。这将发生在哪个版本尚未确定。

这个答案是基于Stefaan Lippens的另一个解决方案,它将你从Python的循环导入洞中挖出来。

模块a.py:

import b
print("This is from module a")

模块b.py

import a
print("This is from module b")

运行“Module a”将输出:

>>> 
'This is from module a'
'This is from module b'
'This is from module a'
>>> 

它输出了这3行,而由于循环导入,它应该输出不定式。 这里列出了运行“模块a”时逐行发生的事情:

The first line is import b. so it will visit module b The first line at module b is import a. so it will visit module a The first line at module a is import b but note that this line won't be executed again anymore, because every file in python execute an import line just for once, it does not matter where or when it is executed. so it will pass to the next line and print "This is from module a". After finish visiting whole module a from module b, we are still at module b. so the next line will print "This is from module b" Module b lines are executed completely. so we will go back to module a where we started module b. import b line have been executed already and won't be executed again. the next line will print "This is from module a" and program will be finished.

去年在comp.lang.python上对此进行了很好的讨论。它很彻底地回答了你的问题。

Imports are pretty straightforward really. Just remember the following: 'import' and 'from xxx import yyy' are executable statements. They execute when the running program reaches that line. If a module is not in sys.modules, then an import creates the new module entry in sys.modules and then executes the code in the module. It does not return control to the calling module until the execution has completed. If a module does exist in sys.modules then an import simply returns that module whether or not it has completed executing. That is the reason why cyclic imports may return modules which appear to be partly empty. Finally, the executing script runs in a module named __main__, importing the script under its own name will create a new module unrelated to __main__. Take that lot together and you shouldn't get any surprises when importing modules.

我用下面的方法解决了这个问题,没有任何错误。 考虑两个文件a.py和b.py。

我把这个添加到a.py,它工作了。

if __name__ == "__main__":
        main ()

a.py:

import b
y = 2
def main():
    print ("a out")
    print (b.x)

if __name__ == "__main__":
    main ()

b.py:

import a
print ("b out")
x = 3 + a.y

得到的输出是

>>> b out 
>>> a out 
>>> 5