2017-04-03 24 views
4

衆所周知,您可以通過del sys.modules[module]刪除導入的模塊。所以我在想:這與改寫sys.modules有什麼不同?一個有趣的事實是,重寫sys.modules不能真正刪除一個模塊。「del sys.modules [模塊]」實際上做了什麼?

# a_module.py 
print("a module imported") 

然後

import sys 

def func1(): 
    import a_module 
    # del sys.modules['a_module'] 
    sys.modules = { 
     k: v for k, v in sys.modules.items() if 'a_module' not in k} 
    print('a_module' not in sys.modules) # True 

def func2(): 
    import a_module 

func1() # a module imported 
func2() # no output here 

如果我使用del sys.modules['a_module'],呼籲func2()還打印a module imported,這意味着a_module被成功刪除。

我的問題是:del sys.modules[module]實際上做了什麼,除了更改字典?

回答

6

sys.modulesPython的可訪問的參考規範數據結構用於跟蹤模塊被導入的內容。從該字典中刪除名稱意味着將來任何導入模塊的嘗試都將導致Python從頭開始加載模塊。

換句話說,當你使用import聲明,第一件事Python做是檢查字典,sys.modules引用已經擁有該模塊的一個條目,並進行下一步(在當前名字空間綁定名稱),而不進行首先加載模塊。如果您從sys.modules中刪除條目,那麼Python將不會找到已經加載的模塊並再次加載。

請注意關於Python可訪問的的注意措詞。實際的字典生活在Python堆上,sys.modules只是其中的一個參考。您將替換爲,該字典通過分配給sys.modules與另一個字典進行引用。不過,口譯員還有更多參考;他們只是不能從Python代碼訪問,而不是沒有​​詭計來訪問C-API。

注意,這是explicitly documented

但是,更換預期字典不一定會工作,並刪除從字典中的必備物品可能會導致Python的失敗。

從C-API中,您必須使用PyThreadState_Get()->interp->modules來獲取字典的內部引用。

+0

謝謝。這是記錄在某處嗎?我不知道有「更多的參考」。 – laike9m

+0

@ laike9m:很多是實現細節;我在源代碼中進行了深入的深入研究。其他Python實現可能會以不同方式處理解釋器狀態。 –

+1

@ laike9m:例如,我注意到[PyInterpreterState]的C-API文檔(https://docs.python.org/3/c-api/init.html#c.PyInterpreterState)沒有提及的任何結構成員,並且'sys.modules'的文檔明確警告不要替換'sys.modules'引用。 –

相關問題