python3中的循环导入和类字段

时间:2017-08-11 11:40:30

标签: python django python-3.x python-import

好的,我确实理解这个话题已经过时了,但我找不到我要问的特定问题的答案。

假设我们的结构非常简单:两个文件a.pyb.py,其内容为:

a.py

import b

class C:
    lal = 4

class A:
    kek = 12
    lol = b.B()

b.py

import a

class B:
    aa = a.C()

尝试运行python b.py,我们得到:

Traceback (most recent call last):
  File "b.py", line 1, in <module>
    import a
  File ".../a.py", line 1, in <module>
    import b
  File ".../b.py", line 3, in <module>
    class B:
  File ".../a.py", line 5, in A                                                                                  
    aa = a.C()
AttributeError: module 'a' has no attribute 'C'

但是如果我们移动import b AFTER C类,则脚本会启动并且不会产生任何错误。

我在SO上的任何答案中都没有提到任何这方面的内容。这里的问题是:为什么会发生这种情况, 如何 来逃避这种情况?

对于Django框架来说,这是一个特别重要的问题。当我有很多模型时,我会尝试将它们分成许多文件。在那里进行循环导入非常容易。

2 个答案:

答案 0 :(得分:1)

在python中导入模块时,它首先导入在模块顶部定义的所有模块,如果模块不在sys.modules中,则导入会在sys.modules中创建新模块条目然后执行模块中的代码。

因此,当您尝试在a.py中导入b.py模块时,如果模块未在sys.modules中列出,则首先导入b.py中列出的所有模块为a.py(导入a)。仍然没有完全执行模块b.​​py所以b.py模块没有添加到sys.modules

之后,它尝试导入a.py并在a.py中尝试首先导入所有在a.py中导入的模块是b.py

所以这是一个基本周期a.py尝试导入b.py和b.py尝试导入a.py

enter image description here

对于该问题,解决方案是在类中导入一个模块或类,而不是在模块的顶部

根据你的例子

<强> a.py

class C:
    lal = 4

class A:
    import b
    kek = 12
    lol = b.B()

<强> b.py

import a

class B:
    aa = a.C() 

<强> a.py

import b
class C:
    lal = 4

class A:

    kek = 12
    lol = b.B()

<强> b.py

class B:
    import a
    aa = a.C() 

详细information discussion

Python issue

答案 1 :(得分:0)

实际上@Kallz已经提供了正确的答案,但你有点顽固:)你正在创建循环引用,它将以无限循环结束。 Python有一个机制,可以逐行逐行避免这种循环。首先打开b.py - 它作为'__main__'加载到sys.modules中并开始加载。加载它时会出现'import a'。所以它寻找模块'a'。它找到它并将其放入sys.modules中。 sys.modules现在有'__main__'和'a'。它开始加载模块'a',遇到'import b'。所以它找到'b.py'并将其放入sys.modules中。现在你有'__main__','a','b',它开始加载'b',遇到'import a' - 这次模块'a'已经在sys.modules中了,加载它已经开始了!所以Python知道正在发生的事情,你自己就是一个ImportError。