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


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


当前回答

Ok, I think I have a pretty cool solution. Let's say you have file a and file b. You have a def or a class in file b that you want to use in module a, but you have something else, either a def, class, or variable from file a that you need in your definition or class in file b. What you can do is, at the bottom of file a, after calling the function or class in file a that is needed in file b, but before calling the function or class from file b that you need for file a, say import b Then, and here is the key part, in all of the definitions or classes in file b that need the def or class from file a (let's call it CLASS), you say from a import CLASS

这是可行的,因为您可以导入文件b,而无需Python执行文件b中的任何导入语句,因此您可以避免任何循环导入。

例如:

文件:

class A(object):

     def __init__(self, name):

         self.name = name

CLASS = A("me")

import b

go = B(6)

go.dostuff

文件b:

class B(object):

     def __init__(self, number):

         self.number = number

     def dostuff(self):

         from a import CLASS

         print "Hello " + CLASS.name + ", " + str(number) + " is an interesting number."

喉咙痛。

其他回答

我完全同意pythoneer的回答。但是我偶然发现了一些代码,它们在循环导入时存在缺陷,并在尝试添加单元测试时引起了问题。因此,为了快速修补它而不改变一切,你可以通过动态导入来解决这个问题。

# Hack to import something without circular import issue
def load_module(name):
    """Load module using imp.find_module"""
    names = name.split(".")
    path = None
    for name in names:
        f, path, info = imp.find_module(name, path)
        path = [path]
    return imp.load_module(name, f, path[0], info)
constants = load_module("app.constants")

同样,这不是一个永久性的修复,但可以帮助那些希望在不修改太多代码的情况下修复导入错误的人。

干杯!

循环导入可能令人困惑,因为导入做了两件事:

它执行导入的模块代码 将导入的模块添加到导入模块全局符号表中

前者只执行一次,而后者则在每个import语句中执行。循环导入会在导入模块使用已导入的模块和部分执行的代码时产生这种情况。因此,它将看不到import语句后创建的对象。下面的代码示例演示了它。

循环进口并不是要不惜一切代价避免的终极祸害。在一些框架中,比如Flask,它们是很自然的,调整你的代码来消除它们并不会让代码变得更好。

main.py

print 'import b'
import b
print 'a in globals() {}'.format('a' in globals())
print 'import a'
import a
print 'a in globals() {}'.format('a' in globals())
if __name__ == '__main__':
    print 'imports done'
    print 'b has y {}, a is b.a {}'.format(hasattr(b, 'y'), a is b.a)

b.by

print "b in, __name__ = {}".format(__name__)
x = 3
print 'b imports a'
import a
y = 5
print "b out"

a.py

print 'a in, __name__ = {}'.format(__name__)
print 'a imports b'
import b
print 'b has x {}'.format(hasattr(b, 'x'))
print 'b has y {}'.format(hasattr(b, 'y'))
print "a out"

Python main.py输出带有注释

import b
b in, __name__ = b    # b code execution started
b imports a
a in, __name__ = a    # a code execution started
a imports b           # b code execution is already in progress
b has x True
b has y False         # b defines y after a import,
a out
b out
a in globals() False  # import only adds a to main global symbol table 
import a
a in globals() True
imports done
b has y True, a is b.a True # all b objects are available

bar.py

print('going to import foo')
from foo import printx

foo.py

print('trying to import bar')
import bar

def printx():
    print('x')
$ python bar.py

going to import foo
trying to import bar
going to import foo
Traceback (most recent call last):
  File "bar.py", line 2, in <module>
    from foo import printx
  File "/home/suhail/Desktop/temp/circularimport/foo.py", line 2, in <module>
    import bar
  File "/home/suhail/Desktop/temp/circularimport/bar.py", line 2, in <module>
    from foo import printx
ImportError: cannot import name 'printx' from partially initialized module 'foo' (most likely due to a circular import) (/home/suhail/Desktop/temp/circularimport/foo.py)

模块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.

这里有个例子让我震惊!

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