技能get:關于Python模塊引入,你真的hold住嗎?
- 分類:行業洞察
- 作者:
- 來源:
- 發布時間:2020-07-14 14:39
- 訪問量:
【概要描述】Python是一門優美簡單、功能強大的動態語言。但在實際項目中總會遇到一些無法避免的問題。今天,天地和興針對“模塊引入”問題進行了細致分析。
技能get:關于Python模塊引入,你真的hold住嗎?
【概要描述】Python是一門優美簡單、功能強大的動態語言。但在實際項目中總會遇到一些無法避免的問題。今天,天地和興針對“模塊引入”問題進行了細致分析。
- 分類:行業洞察
- 作者:
- 來源:
- 發布時間:2020-07-14 14:39
- 訪問量:
Python是一門優美簡單、功能強大的動態語言。在剛剛接觸這門語言時,常常會被其優美的格式、簡潔的語法和無窮無盡的類庫所震撼。在真正地將python應用到實際項目中,總會遇到一些無法避免的問題。最讓人困惑不解的問題有二類,一個是編碼問題,另一個則是模塊引入問題。接下來,針對“模塊引入”問題本文進行了細致分析。
一、問題表象
在某個python項目中,在兩個不同的python模塊A、B中引入了同一個模塊C中的一個類D,該類中存在類變量E。簡化的項目結構如下圖所示。其中A模塊中會設置D中的類變量E的值,模塊B會使用類D中的類變量E。理論上模塊A和模塊B中所見的類屬性E的值是一致的。然而在運行時出現了非常奇怪的現象,模塊A中所見的類變量E是設置后的值,而模塊B中所見的類變量E則是設置前的值。
在python程序運行的過程中,一個類實際上會在程序中的堆內存中體現,也就是說類的數據存儲在一塊堆內存中,其中就包含了該類變量。要出現之前同一個類變量的值不一致,則訪問的是不同的類在堆中的內存。
難道同一個類可以在堆內存中存在于兩塊不同的內存中嗎?
二、問題調試分析
帶著以上疑問,分別在模塊A和模塊B中增加相關的調試打印信息,利用id()方法來獲取各自引入的類在內存中的地址值。兩個模塊打印出來的信息顯示出兩個模塊各自引入的類在內存中的地址值確實不一樣。因為兩個模塊訪問的類在堆內存中地址不一樣,那么之前模塊A設置類變量E的操作是作用在模塊A的類D所在的堆內存,而模塊B所訪問的是模塊B的類D所在的堆內存。
繼續增加打印,觀察模塊A和模塊B所引入的類D的名稱會發現,在模塊A中類D的名稱為pkg1.pkg2.C.D,而在模塊B中類D的名稱為pkg2.C.D,這兩個名稱明顯不同。原來在模塊A中類D的引入語句是“from pkg1.pkg2.C import D”,而模塊B中引入語句是“from pkg2.C import D”。之所以模塊A和模塊B可以有不同的引入方式,是因為之前已經將目錄pkg1的路徑加入sys.path。
三、問題原理解析
想弄清楚上述問題,就得弄清楚import原理。python在處理import時做了2件事情——查找模塊和加載模塊。
查找模塊的流程如下所示:
1. 查找sys.modules是否有該模塊,如果有,直接導入;
2. 查找sys.meta_path。meta_path是一個list,?面保存著一些finder對象,如果找到該module,則返回一個finder對象;
3. 檢查?些隱式的finder對象,不同的python實現有不同的隱式finder,但都會有 sys.path_hooks、sys.path_importer_cache及sys.path;
4. 拋出ImportError。
加載模塊的動作如下所示:
如果請求的模塊已存在 sys.modules,應使用并重新加載該模塊。否則加載器應是創建一個新的模塊并在任何過程開始前將該新模塊插入到 sys.modules 中。
為了更深入分析之前的問題,做了相關測試來驗證sys.modules中保存的模塊信息,看是否對于同一個類,由于引入方式不同,在sys.modules會存在兩個不同模塊。
項目工程如下圖所示:
測試代碼如下所示:
測試結果如下,可以看出針對同一個模塊不同的引入方式,有可能會導致該模塊被多次加載。
對于之前遇到的問題,模塊A引入類模塊D的方式會在sys.modules中加載pkg1.pkg2.C.D,而對于模塊B,會在sys.modules中加載pkg2.C.D。而對于sys.modules來說,這是兩個不同模塊,也就開辟了兩塊堆內存空間,直接導致當模塊A對類D的類變量E做出修改后,模塊A和模塊B中所見的類屬性E的值不一致。
四、結論
通過上述問題的原因分析可知,在python程序中必須要注意模塊的引入方式,對同一個模塊的引用盡量要保證引入方式的一致性。這類問題有比較強的隱蔽性,因此從一開始就應該使用代碼規范的角度來規避此類問題。

公司總部:北京市海淀區中關村軟件園8號華夏科技大廈三層
服務熱線:400-810-8981 / 010-82896289
版權所有:北京天地和興科技有限公司 京ICP備17065546號-1

掃一掃關注
天地和興微信公眾號