簡介:
在使用Python編寫項目時,我們經常使用import xx
或者from xx import a
去導入其他模塊或者其他模塊中的一些對象和方法,那么這兩個語句有什么不一樣的呢。在此處,做一下總結,讓自己對它們的原理進行一些了解。
方法:
==
Python提供了三種方法引入外部模塊,import
語句、from...import...
和__import__
函數。我們最為常用的是前兩者。對于第三種方式,它與import
語句類似,只是前者顯式的將模塊的名稱作為字符串傳遞并賦值給命名空間的變量。
注意事項:
- 盡量優先使用
import
語句,如import a.B
,可以訪問B - 有節制的使用
from a import B
形式,但是這樣也可以直接訪問B - 避免使用
from a import *
形式,這樣會污染命名空間,并且導入了哪些模塊也不清晰。
import的原理
Python的import機制,在Python初始化運行環境時候會預先加載一批內建模塊到內存中,這些模塊相關的信息存放在了sys.modules
中,用戶導入sys
模塊后使用sys.modules.items()
可以顯示所有預加載模塊的相關信息。
當加載一個模塊時,Python解釋器做了以下一些事情:
- 在
sys.modules
中進行搜索,如果該模塊已經存在,就將該模塊導入到當前局部命名空間。加載就結束了。 - 如果在
sys.modules
中找不到該模塊的名稱,則為需要導入的模塊創建一個字典對象,并將該對象信息插入到sys.modules
中。 - 加載前確認是否需要對模塊對應的文件進行編譯,如果需要編譯就要進行編譯。
- 執行動態加載,在當前模塊中的命名空間中執行編譯后的字節碼文件,并將其中所有的對象放入到模塊對應的字典中。
無節制使用from...import...帶來的問題
命名空間沖突
例子:有如下三個文件
在模塊a和模塊b中都定義了add()
函數。那么我們在test文件中使用from...import...
的形式導入add
時,最終起作用的是哪一個呢?
# filename a.py
def add():
print("add in module A")
# filename b.py
def add():
print("add in module B")
# filename test.py
from a import add
from b import add
if __name__ == '__main__':
add()
運行test.py之后,我們得到輸出:
"add in module B"
也就是說在這里起作用的是最近導入的add(),它完全覆蓋了當前命名空間中之前導入的模塊a中的add().所以在大型的項目中,我們所包含的包和模塊數目非常多,因此使用from...import...
語句將會大大增加了命名空間沖突的概率,很大可能會導致出現無法預料的錯誤和問題。所有有必要有節制的使用from...import...
語句。
當然在以下的一些情況中可以考慮使用
from...import...
語句
- 當只需要導入部分屬性或者方法時。
- 模塊中的某些屬性和方法使用頻率很高導致使用
a.B
這種形式進行訪問過于煩瑣時。 - 某模塊的文檔明確說明需要使用
from...import
形式,能后更為簡單
和便利時。如使用from io.drivers import zip
要比使用import iodrivers.zip
更加方便。
循環嵌套導入問題
例子:
# filename c1.py
from c2 import g
def x():
pass
# filename c2.py
from c1 import x
def g():
pass
像上邊的兩個文件,無論運行哪一個,都會報出ImportError
的錯誤。解析如下:
- 在執行
c1.py
的加載過程的時候需要創建新的模塊對象c1然后執行c1.py所對應的字節碼,此時遇到語句from c2 import g
,而此時c2在sys.modules中并不存在。然后就會創建與c2對應的模塊對象并執行c2.py, - 而在執行c2.py時候,又遇到
from c1 import x
語句,此時的c1對象雖然已經存在,但是初始化的過程并未完成,所以不存在x對象,所以c2也無法初始化完成。 - 再次執行c1.py時,就會報出
ImportError: cannot import name g
異常。
而使用import可以解決這個問題。
修改文件如下:
# filename c1.py
import c2
def x():
pass
# filename c2.py
import c1
def g():
pass
此時就可以運行這兩個文件了。
參考資料:
編寫高質量代碼:改善Python程序的91個建議