python中的import(涉及pkgutil和inspect包)


python中萬物皆對象。維度比較大的有模塊、包。

一個.py文件就是一個python模塊(module),如果一個目錄下面有一個__init__.py文件,那么這個目錄就是一個python包(package)。

當(dāng)然,這只是極簡版的概念。實際上包是一種特殊的模塊,而任何定義了__path__
屬性的模塊都被當(dāng)做包。

以兩個下劃線開頭,以兩個下劃線結(jié)尾的屬性,暫稱魔法屬性(自創(chuàng)的),對應(yīng)的有魔法方法。——用特別的格式表示能實現(xiàn)一些特別的功能。

在python代碼中使用模塊或包,需要使用import語句。

有兩種import方法:relative import和absolute import。

相對導(dǎo)入,是通過指出相對當(dāng)前目錄位置的偏移來導(dǎo)入對應(yīng)目錄下的模塊。

絕對導(dǎo)入,就是直接指出哪個包,哪個模塊。

當(dāng)python解釋器看到import語句后,要做兩件事:找到module,將module加入到local namespace中。

具體就是,根據(jù)import的指示,去尋找(find_module)到對應(yīng)的module,并導(dǎo)入(load_module)了。

在第一步查找時,遵循:

  1. 檢查 sys.modules (保存了之前import的類庫的緩存),如果module被找到,則?到第二步。
  1. 檢查 sys.meta_path。meta_path 是一個 list,?面保存著一些 finder 對象,如果找到該module的話,就會返回一個finder對象。
  2. 檢查?些隱式的finder對象,不同的python實現(xiàn)有不同的隱式finder,但是都會有 sys.path_hooks, sys.path_importer_cache 以及sys.path。
  3. 拋出 ImportError。

詳細(xì)內(nèi)容可以參考:
Python Import 機制與拓展
Python 的 import 機制

這里說幾個典型應(yīng)用吧。

判斷模塊是否已導(dǎo)入
若已導(dǎo)入,必定在sys.modules中。sys.modules是已導(dǎo)入模塊的字典,key是模塊名,value是模塊對象。

獲取某已導(dǎo)入模塊的所有屬性
dir(sys.modules[module_name])獲取對應(yīng)key==module_namevalue值。
help(dir)的輸出:

Help on built-in function dir in module __builtin__:

dir(...)
    dir([object]) -> list of strings

    If called without an argument, return the names in the current scope.
    Else, return an alphabetized list of names comprising (some of) the attributes
    of the given object, and of attributes reachable from it.
    If the object supplies a method named __dir__, it will be used; otherwise
    the default dir() logic is used and returns:
      for a module object: the module's attributes.
      for a class object:  its attributes, and recursively the attributes
        of its bases.
      for any other object: its attributes, its class's attributes, and
        recursively the attributes of its class's base classes.

在其中提到了,可以使用__dir__魔法方法來自定義。

之后在inspect或是需要了解對象內(nèi)部的情況時,還會用到它。

為什么會報ImportError,如何規(guī)定導(dǎo)入路徑
sys.path 是當(dāng)前環(huán)境的module搜索路徑,如果想要找到某package,就需要將此package的目錄加入到這個list當(dāng)中,也就是對應(yīng)package中的__init__.py文件所在的目錄。

如使用pip安裝的包就位于'/Library/Python/2.7/site-packages'目錄。

通常,在這個列表中,會加入當(dāng)前目錄。

一個關(guān)于Class A和Class B遞歸導(dǎo)入的經(jīng)典問題
import 迷宮

sys.meta_path和其他path hook的區(qū)別
處理sys.path時會使用sys.path_hooks,它會順序地檢查sys.path中的每一項,如不能處理則拋出ImportError,如果可以返回一個importer對象,并返回。
sys.meta_path見下。

自定義導(dǎo)入,寫一個import hook
可以通過import hook,來在模塊導(dǎo)入時做一些工作。

我們已經(jīng)知道,導(dǎo)入模塊首先是要進(jìn)行查找。而查找的第一步是檢查sys.modules,第二步是檢查sys.meta_path,使用其中的finder對象來查找所需要的module。
正常情況下,sys.meta_path是一個空列表。

finder對象必須實現(xiàn)find_module()方法,它可以找到模塊,并返回一個load_module()方法。
loader對象負(fù)責(zé)加載模塊,必須實現(xiàn)load_module()方法。
importer對象,實現(xiàn)了find_module()load_module()方法,即在實際中,只需要實現(xiàn)一個importer類,此類有find_module()load_module()兩個方法。

具體可見上面引用的第一篇blog。

函數(shù)、類屬于哪個模塊
在一個文件中,可以通過from module_name import function_name或者from module_name import class_name,來導(dǎo)入其他模塊的函數(shù),或類。

在這種情況下,會發(fā)現(xiàn)這些導(dǎo)入的對象,也存在于該模塊的dir輸出中。

可以通過這些對象的__module__魔法屬性來判斷是在本模塊中定義,還是從外部導(dǎo)入。

使用這個方法,也可以得知某一方法是與類屬于同一模塊,還是繼承自基類(我并沒有去驗證基類和子類屬于同一模塊的情況,這種情況應(yīng)該比較罕見吧?)。

相對導(dǎo)入和絕對導(dǎo)入

絕對導(dǎo)入就是明確指出是從哪個包或模塊導(dǎo)入。

相對導(dǎo)入是指相對于目前模塊所處的文件位置,來找到某個模塊來導(dǎo)入。如from . import xxx是從當(dāng)前模塊所在的文件的同層目錄中尋找,一個點表示同層目錄,兩個點表示上一層目錄,以此類推。

相對導(dǎo)入會有一些麻煩。推薦使用絕對導(dǎo)入,這也是python推薦的。通過設(shè)置sys.path來將路徑加入,這樣在import時,python會到設(shè)置的路徑中自動匹配。

pkgutil

最常用的有兩個:

iter_modules(path=None, prefix='')
Yields (module_loader, name, ispkg) for all submodules on path, or, if path is None, all top-level modules on sys.path.
path是包的目錄路徑,prefix是輸出時,所有包的名字的前綴。用來獲取該path下的子模塊或子包。

walk_packages(path=None, prefix='', onerror=None)
Yields (module_loader, name, ispkg) for all modules recursively on path, or, if path is None, all accessible modules.
同上,但是這個方法是遞歸獲取路徑下的所有模塊。

inspect

常同pkgutil結(jié)合用。

getmembers(object, predicate=None)
返回object的所有屬性,即dir中的各項。
這些屬性各種各樣,通過設(shè)置predicate來進(jìn)行篩選,如當(dāng)predicate=ismethod,只有當(dāng)其為類的方法時,才會被選中。

getdoc(object)
獲取對象的docstring,即__doc__

getargspec(func)
獲取函數(shù)對象的arg。

還有很多其他方法,詳見inspect的幫助文檔。


最后的TODO

最近在做一個自動化測試的項目,第一步就是要找到所有的模塊、類、方法、函數(shù),以上就是涉及到的一部分基礎(chǔ)知識。

過程中,發(fā)現(xiàn)dir輸出的內(nèi)容要遠(yuǎn)遠(yuǎn)多于真實在代碼里寫出來的東西,對于方法或?qū)傩?,也需要去了解一下?/p>

Python 魔術(shù)方法指南可以起到一定的幫助作用,剩下的還需要繼續(xù)搜索。


其他相關(guān)博文:
python非侵入式代碼監(jiān)控(一): python import hook
PEP 302 -- New Import Hooks
PEP 369 -- Post import hooks
Python源碼剖析筆記5-模塊機制

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 模塊和包 一 模塊 1 什么是模塊? 常見的場景:一個模塊就是一個包含了python定義和聲明的文件,文件名就是...
    go以恒閱讀 2,344評論 0 4
  • 當(dāng)前目錄 和 腳本目錄 參考資料:https://techibee.com/python/get-current-...
    ThomasYoungK閱讀 11,854評論 0 11
  • If you quit from the Python interpreter and enter it agai...
    linyk3閱讀 460評論 0 0
  • IO密集型程序、深拷貝和淺拷貝、模塊導(dǎo)入、with 語句 1.1 GIL 學(xué)習(xí)目標(biāo) 1. 能夠說出 GIL 是什...
    Cestine閱讀 1,123評論 0 0
  • [TOC] 最開始寫程序的時候,都是一個文件里輸入幾行源碼(python 的一個 web 框架bottle就特別強...
    人世間閱讀 5,885評論 1 10

友情鏈接更多精彩內(nèi)容