2016-12-02 39 views
1

每當我想我理解Python導入的細節(最後!)時,新的東西讓我回到了現實。請看看這個簡單的例子:單個文件 - 兩個模塊

文件t1.py

import t2 

x = "waiting for init" 

def init(): 
    global x 
    x = "OK" 

if __name__ == '__main__': 
    init() 
    print("x =", x) 
    t2.print_x() 

注意不要使用不正確from t1 import x,這裏是文件t2.py

import t1 

def print_x(): 
    print("t1.x =", t1.x) 

反正輸出不我期望的:

$ python3 t1.py 

x = OK 
t1.x = waiting for init 

因此x in t1t1.x不同!


經過一番調查這個版本的t2.py幫我一點點:

import t1 

def print_x(): 
    import sys 
    print(sys.modules['t1'].x) 
    print(sys.modules['__main__'].x) 

這兩個打印輸出:

waiting for init 
OK 

我覺得很困惑。單個文件t1.py同時被稱爲兩個不同的模塊:t1__main__。你能向我解釋一下它的含義嗎?在發佈的代碼中必須更改什麼才能獲得t1.x = "OK"

+2

我不確定它是否會影響此特定問題,但您有循環導入 - t1導入t2,t2導入t1。不要這樣做。 –

回答

1

TL; DR:是的,您有兩個從t1.py源創建的內存模塊。

原因是Python的導入系統處理__main__模塊。基本上,它不會這樣做。

__main__模塊不是通過Python的標準導入機制導入,而是通過類似於內置插件的方式進行初始化。

這就是爲什麼,當t1t1在你的代碼輸入,你實際上它進口一次

做實驗很容易。您t1.py模塊的代碼改成這樣:

import t2 

x = "waiting for init" 

if __name__ == "t1": 
    print("t1.x = ", x) 

if __name__ == '__main__': 
    print("__main__.x =", x) 

而且你會看到下一個控制檯打印:

t1.x = waiting for init 
__main__.x = waiting for init 

現在評論這個模塊中的第一行,你會得到這樣的:

__main__.x = waiting for init 

所以,在第一種情況下,模塊t1首先初始化(被執行它的代碼)由解釋器的啓動mechanizm作爲__main__ ,然後t1從t2模塊中由Python的導入系統初始化(因此再次執行)。

在第二種情況下,模塊僅由解釋器啓動mechanizm進行初始化。

PS。從@ShadowRanger尼斯抓在下面的評論:在腳本的末尾打印sys.modules會告訴你是這樣的:

<module '__main__' from 't1.py'> 
<module 't1' from 'D:\\Projects\\python_test\\t1.py'> 

表明模塊從相同的源創建的。

+1

另一個有用的測試:在'__main__'處理代碼中,do:'import sys','print(「__ main__ same to t1?」,sys.modules ['__ main__'] is sys.modules ['t1'])' (這依賴't1'由於導入't2'而被緩存)。它會報告「假」;如果兩個緩存條目都被初始化爲完全相同的東西,它只會報告「真」。 – ShadowRanger

+0

謝謝你的解釋。 「......再次輸入」這句話是關鍵。我的結論是「從不導入入口點文件」(帶有if __name__ =='__main __'的文件)。對? – VPfB

+0

帶'if _name__ =='__main __'的@VPFB文件不是必需的主腳本。你可以使用這個條件,例如出於測試目的,此代碼的主要目的是在兩種情況下(模塊導入時以及模塊作爲主腳本運行時)分離模塊的行爲。所以正確的答案是當模塊已經作爲腳本運行時不會導入模塊。這種情況實際上沒什麼意義,並且基本顯示了應用程序的體系結構缺陷。 –

相關問題