簡體   English   中英

導入模塊:__main__ vs作為模塊導入

[英]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__'] ,但是func1Bsys.modules['mod1']查找var1 ,其中為None

但是,當您使用python driver.pydriver.py成為程序的'__main__'主文件,並且mod1將僅一次導入sys.modules['mod1']結構中。 這次, func1Avar1存儲在sys.modules['mod1']結構中,這就是func1B會發現的。

關於將模塊可選地用作主腳本的實用解決方案-支持一致的交叉導入:

解決方案1:

參見例如在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
...

這樣,模塊主體不會執行兩次-這是“昂貴的”,不希望的,有時甚至很關鍵。

解決方案2:

在極少數情況下,最好甚至將實際腳本模塊__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_globalfind_global ..)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM