2017-08-11 66 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 bC類,腳本啓動,併產生沒有錯誤。

我還沒有發現這個任何提及任何在這裏,所以任何答案。這裏的問題是:爲什麼會出現這種情況和如何逃脫呢?

這是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版本的加載看起來不一樣。你在使用哪一個? –