Python中標(biāo)準(zhǔn)模塊importlib詳解
1 模塊簡(jiǎn)介
Python提供了importlib包作為標(biāo)準(zhǔn)庫(kù)的一部分。目的就是提供Python中import語(yǔ)句的實(shí)現(xiàn)(以及__import__函數(shù))。另外,importlib允許程序員創(chuàng)建他們自定義的對(duì)象,可用于引入過(guò)程(也稱(chēng)為importer)。
什么是imp?
另外有一個(gè)叫做imp的模塊,它提供給Python import語(yǔ)句機(jī)制的接口。這個(gè)模塊在Python 3.4中被否決,目的就是為了只使用importlib。
這個(gè)模塊有些復(fù)雜,因此我們?cè)谶@篇博文中主要討論以下幾個(gè)主題:
•動(dòng)態(tài)引入
•檢查模塊是否可以被引入
•引入源文件自身
•第三方模塊 import_from_github_com
2 模塊使用
2.1 動(dòng)態(tài)引入
importlib模塊支持傳入字符串來(lái)引入一個(gè)模塊。我們創(chuàng)建兩個(gè)簡(jiǎn)單的模塊來(lái)驗(yàn)證這個(gè)功能。我們將會(huì)給予兩個(gè)模塊相同的接口,讓它們打印名字以便我們能夠區(qū)分它們。創(chuàng)建兩個(gè)模塊,分別為foo.py和bar.py,代碼如下所示,
def main(): print(__name__)
現(xiàn)在我們使用importlib來(lái)引入它們。讓我們看看這段代碼如何去做的。確保你已經(jīng)把這段代碼放在與上面創(chuàng)建的兩個(gè)模塊相同的目錄下。
#importer.py import importlib def dynamic_import(module): return importlib.import_module(module) if __name__ == "__main__": module = dynamic_import('foo') module.main() module_two = dynamic_import('bar') module_two()
在這段代碼中,我們手動(dòng)引入importlib模塊,并創(chuàng)建一個(gè)簡(jiǎn)單的函數(shù)dynamic_import。這個(gè)函數(shù)所做的就是調(diào)用importlib模塊中的import_module函數(shù),入?yún)⒕褪俏覀儌魅氲淖址?,然后返回調(diào)用結(jié)果。在代碼段的下面,我們調(diào)用每個(gè)模塊的main方法,將會(huì)打印出每個(gè)模塊的名稱(chēng)。
在你的代碼中,你可能不會(huì)大量這樣做。當(dāng)你只有一個(gè)字符串時(shí),如果你想引入這個(gè)模塊,importlib就允許你可以這么做。
2.2 模塊引入檢查
Python有一個(gè)編碼規(guī)范就是EAPP:Easier to ask for forgiveness than permision。意思就是經(jīng)常假設(shè)一些事情是存在的(例如,key在詞典中),如果出錯(cuò)了,那么就捕獲異常。你可以看 Python標(biāo)準(zhǔn)模塊--import 文章中我們嘗試引入模塊,當(dāng)它不存在時(shí),我們就會(huì)捕獲到ImportError。如果我們想檢查并觀察一個(gè)模塊是否可以引入而不是僅僅是猜測(cè),該如何去做?你可以使用importlib。代碼如下:
#coding:utf-8 import importlib.util import importlib def check_module(module_name): module_spec = importlib.util.find_spec(module_name) if module_spec is None: print("Module :{} not found".format(module_name)) return None else: print("Module:{} can be imported!".format(module_name)) return module_spec def import_module_from_spec(module_spec): module = importlib.util.module_from_spec(module_spec) module_spec.loader.exec_module(module) return module if __name__ == "__main__": module_spec = check_module("fake_module") module_spec = check_module("collections") if(module_spec): module = import_module_from_spec(module_spec) print(dir(module))
這里我們引入importlib模塊的子模塊util。在check_module函數(shù)中,我們調(diào)用find_spec函數(shù)來(lái)檢查傳入的字符串作為模塊是否存在。首先,我們傳入一個(gè)假的名稱(chēng),然后我們傳入一個(gè)Python模塊的真實(shí)名稱(chēng)。如果你運(yùn)行這段代碼,你將會(huì)看到你傳入一個(gè)沒(méi)有安裝的模塊的名稱(chēng),find_spec函數(shù)將會(huì)返回None,我們的代碼將會(huì)打印出這個(gè)模塊沒(méi)有找到。如果找到了,我們就會(huì)返回模塊的說(shuō)明。
我們可以獲取到模塊的說(shuō)明,然后使用它來(lái)真正的引入模塊?;蛘吣憧梢詫⒆址畟魅氲絠mport_module函數(shù)中,正如我們?cè)?.1節(jié)中所學(xué)習(xí)到的一樣。但是我們已經(jīng)學(xué)習(xí)到如何使用模塊的說(shuō)明。讓我們看一下上述代碼中的import_module_from_spec函數(shù)。它接受由check_module函數(shù)返回的模塊說(shuō)明。我們將其傳入到module_from_spec函數(shù),它將會(huì)返回引入的模塊。Python的官方文檔推薦,在引入模塊后執(zhí)行它,所以我們下一步做的就是調(diào)用exec_module函數(shù)。最后我們返回這個(gè)模塊,并且運(yùn)行Python的dir函數(shù)來(lái)確認(rèn)這個(gè)我們就是我們所期望的。
2.3 從源文件中引入
在這一節(jié)中,我想說(shuō)明importlib的子模塊util還有另外一個(gè)技巧。你可以使用util通過(guò)模塊名和文件路徑來(lái)引入一個(gè)模塊。示例如下所示,
#coding:utf-8 import importlib.util def import_source(module_name): module_file_path = module_name.__file__ module_name = module_name.__name__ module_spec = importlib.util.spec_from_file_location(module_name,module_file_path) module = importlib.util.module_from_spec(module_spec) module_spec.loader.exec_module(module) print(dir(module)) msg = "The {module_name} module has the following methods:{methods}" print(msg.format(module_name = module_name,methods = dir(module))) if __name__ == "__main__": import logging import_source(logging)
上述代碼中,我們實(shí)際引入了logging模塊,并將它傳入到import_source函數(shù)。在這個(gè)函數(shù)中,我們首先獲取到模塊的實(shí)際路徑和名稱(chēng)。然后我們將這些信息傳入到util的spec_from_file_location函數(shù)中,這個(gè)將會(huì)返回模塊的說(shuō)明。一旦我們獲取到模塊的說(shuō)明,我們就可以使用與2.2節(jié)相同的importlib機(jī)制來(lái)實(shí)際引入模塊。
現(xiàn)在讓我們來(lái)看一個(gè)精巧的第三方庫(kù),Python的__import__()函數(shù)直接引入github中的包。
2.4 import_from_github_com
這個(gè)精巧的包叫做import_from_github_com,它可以用于發(fā)現(xiàn)和下載github上的包。為了安裝他,你需要做的就是按照如下命令使用pip,
pip install import_from_github_com
這個(gè)包使用了PEP 302中新的引入鉤子,允許你可以從github上引入包。這個(gè)包實(shí)際做的就是安裝這個(gè)包并將它添加到本地。你需要Python 3.2或者更高的版本,git和pip才能使用這個(gè)包。
一旦這些已經(jīng)安裝,你可以在Python shell中輸入如下命令,
>>> from github_com.zzzeek import sqlalchemy Collecting git+https://github.com/zzzeek/sqlalchemy Cloning https://github.com/zzzeek/sqlalchemy to /tmp/pip-acfv7t06-build Installing collected packages: SQLAlchemy Running setup.py install for SQLAlchemy ... done Successfully installed SQLAlchemy-1.1.0b1.dev0 >>> locals() {'__builtins__': <module 'builtins' (built-in)>, '__spec__': None, '__package__': None, '__doc__': None, '__name__': '__main__', 'sqlalchemy': <module 'sqlalchemy' from '/usr/local/lib/python3.5/site-packages/\ sqlalchemy/__init__.py'>, '__loader__': <class '_frozen_importlib.BuiltinImporter'>}
你如果看了import_from_github_com的源碼,你將會(huì)注意到它并沒(méi)有使用importlib。實(shí)際上,它使用了pip來(lái)安裝那些沒(méi)有安裝的包,然后使用Python的__import__()函數(shù)來(lái)引入新安裝的模塊。這段代碼非常值得學(xué)習(xí)。
2.5 總結(jié)
到這里,你已經(jīng)了解到在你的代碼中如何使用importlib和引入鉤子。當(dāng)然還有很多超出本文所覆蓋的知識(shí),如果你需要寫(xiě)一個(gè)自定義的引入器或者下載器,你需要花費(fèi)很多時(shí)間來(lái)閱讀官方文檔和源碼。
相關(guān)文章
python項(xiàng)目對(duì)接釘釘SDK的實(shí)現(xiàn)
這篇文章主要介紹了python項(xiàng)目對(duì)接釘釘SDK的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-07-07

使用memory_profiler監(jiān)測(cè)python代碼運(yùn)行時(shí)內(nèi)存消耗方法

Python?Opencv實(shí)現(xiàn)圖片切割處理

Python通用驗(yàn)證碼識(shí)別OCR庫(kù)ddddocr的安裝使用教程

Matplotlib實(shí)戰(zhàn)之堆疊面積圖繪制詳解

Python實(shí)現(xiàn)數(shù)據(jù)可視化大屏布局的示例詳解

Python button選取本地圖片并顯示的實(shí)例