[英]Importing modules: __main__ vs import as module
作為序言,我想我可能已經弄清楚了如何使此代碼正常工作(基於import之后更改模塊變量 ),但是我的問題確實是關於為什么會發生以下行為,以便我將來可以做什么。
我有三個文件。 第一個是mod1.py:
# mod1.py
import mod2
var1A = None
def func1A():
global var1
var1 = 'A'
mod2.func2()
def func1B():
global var1
print var1
if __name__ == '__main__':
func1A()
接下來我有mod2.py:
# mod2.py
import mod1
def func2():
mod1.func1B()
最后我有driver.py:
# driver.py
import mod1
if __name__ == '__main__':
mod1.func1A()
如果我執行命令python mod1.py
則輸出為None
。 根據我上面提到的鏈路上,似乎有一些區分mod1.py
為被進口__main__
和mod1.py
正在從進口mod2.py
。 因此,我創建了driver.py
。 如果執行命令python driver.py
則會得到預期的輸出: A
。 我看到了一些區別,但是我並沒有真正看到它的機制或原因。 這是怎么發生的以及為什么發生的? 似乎同一模塊將存在兩次是違反直覺的。 如果我執行python mod1.py
,是否可以訪問mod1.py
的__main__
版本中的變量,而不是mod2.py
導入的版本中的變量?
__name__
變量始終包含模塊的名稱, 除非文件已作為腳本加載到解釋器中。 然后將該變量設置為字符串'__main__'
。
畢竟,腳本隨后將作為整個程序的主文件運行,其他所有文件都是該主文件直接或間接導入的模塊。 通過測試__name__
變量,您可以因此檢測文件是作為模塊導入的還是直接運行的。
在內部,為模塊提供了一個命名空間字典,該字典作為每個模塊的元數據的一部分存儲在sys.modules
。 主文件(已執行的腳本)以與'__main__'
相同的結構存儲。
但是,當您將文件導入為模塊時,python首先在sys.modules
查找該模塊是否已經導入。 因此, import mod1
意味着我們首先在sys.modules
查找mod1
模塊。 如果還沒有mod1
它將創建一個帶有名稱空間的新模塊結構。
因此,如果您都將mod1.py
作為主文件運行, 然后將其作為python模塊導入,則它將在sys.modules
獲得兩個命名空間條目。 一個是'__main__'
,然后是'mod1'
。 這兩個名稱空間是完全分開的。 您的全局var1
存儲在sys.modules['__main__']
,但是func1B
在sys.modules['mod1']
查找var1
,其中為None
。
但是,當您使用python driver.py
, driver.py
成為程序的'__main__'
主文件,並且mod1
將僅一次導入sys.modules['mod1']
結構中。 這次, func1A
將var1
存儲在sys.modules['mod1']
結構中,這就是func1B
會發現的。
關於將模塊可選地用作主腳本的實用解決方案-支持一致的交叉導入:
參見例如在Python的pdb模塊中,如何在以__main__
(最后)執行時通過導入自身將其作為腳本運行:
#! /usr/bin/env python
"""A Python debugger."""
# (See pdb.doc for documentation.)
import sys
import linecache
...
# When invoked as main program, invoke the debugger on a script
if __name__ == '__main__':
import pdb
pdb.main()
我只是建議將__main__
啟動重新組織為腳本的開頭,如下所示:
#! /usr/bin/env python
"""A Python debugger."""
# When invoked as main program, invoke the debugger on a script
import sys
if __name__ == '__main__':
##assert os.path.splitext(os.path.basename(__file__))[0] == 'pdb'
import pdb
pdb.main()
sys.exit(0)
import linecache
...
這樣,模塊主體不會執行兩次-這是“昂貴的”,不希望的,有時甚至很關鍵。
在極少數情況下,最好甚至將實際腳本模塊__main__
公開為實際模塊別名( mod1
):
# mod1.py
import mod2
...
if __name__ == '__main__':
# use main script directly as cross-importable module
_mod = sys.modules['mod1'] = sys.modules[__name__]
##_modname = os.path.splitext(os.path.basename(os.path.realpath(__file__)))[0]
##_mod = sys.modules[_modname] = sys.modules[__name__]
func1A()
已知缺點:
reload(_mod)
失敗 find_global
( find_global
..)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.