2017-08-11 50 views
0

好吧,我不明白,这个话题是老得要命,但我无法找到答案,我问特定问题。圆形进口和类字段python3

比方说,我们有一个非常简单的结构:两个文件,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线C类,脚本启动,并产生没有错误。

我还没有发现这个任何提及任何在这里,所以任何答案。这里的问题是:为什么会出现这种情况和如何逃脱呢?

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

+0

我不是很受这个领域的教育,但我相信答案在这里:https://docs.python.org/3/reference/import.html。我也建议使用“from module_x import class_y”而不是“import *”。它可以帮助我们避免这些问题。 –

+0

在加载程序执行模块代码之前,模块将存在于sys.modules中。这是至关重要的,因为模块代码可能(直接或间接)导入自己;事先将它添加到sys.modules可以防止在最坏的情况下进行无限递归,并在最佳情况下多次加载。 –

回答

1

在python中,当你导入一个模块时,它首先导入定义在模块顶部的所有模块,如果一个模块不在sys.modules中,那么导入会在sys.modules中创建新的模块入口,然后执行模块中的代码。

,所以当你试图导入b.py模块a.py那么它首先导入,在b.py列出的所有模块a.py(导入),如果模块没有在sys.modules中列出。和蒸馏器模块b.py没有完全执行,从而b.py模块没有加入到sys.modules中

后,它会尝试导入a.py和a.py它首次尝试导入,在一个导入所有模块的.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() 

一个。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

+0

正如我在答复中所表明的那样,我知道这是一个解决方案。但我不明白为什么。这可能是一件坏事,因为所有的导入应该位于文件的顶部。 – feakuru

+0

@feakuru检查我更新的答案 – Kallz

+0

它并不是真的。如果这是一个循环,那么将会有一个完全的其他错误。此外,你的修复(工作,*,因为我表明我知道*)实际上不会解决这个问题 - 它仍然是循环的。 – feakuru

0

其实@Kallz已经提供正确的答案,但你正在有点固执:)您正在创建以无限循环结束的循环引用。 Python有一个机制来逐行地避免这种循环。首先打开b.py - 它以'__main__'的形式加载到sys.modules中并开始加载。加载时,它会涉及到“导入一个”。所以它寻找模块'a'。它找到它并将其放入sys.modules中。 sys.modules现在有'__main__'和'a'。它在遇到'导入b'的地方开始加载模块'a'。所以它找到'b.py'并将其放入sys.modules中。现在你有'__main__','a','b',它开始加载'b',它遇到'导入a' - 这个时间模块'a'已经在sys.modules中,并且它已经开始加载了!所以Python知道一些可怕的事情正在发生,你会得到一个ImportError。

+0

你可能注意到,我没有得到一个'ImportError'。我得到一个'AttributeError'。这表明python认为模块已经加载,只是它不包含'C'。这就是问题所在。 – feakuru

+0

在p3.6上,我在同一个问题集上得到了ImportError! –

+0

python版本的加载看起来不一样。你在使用哪一个? –