上一篇內容我們詳細了解了Python使用inspect模塊獲取一個模塊、類、實例、函數的信息及幫助文檔的方法(參見新手入門到進階,你不可不知的模塊,用Python獲取對象的詳細信息)。
今天,我們繼續領略inspect模塊的一些高級用法——使用inspect模塊獲取一個類的層次結構和類的繼承順序。
無聊的文檔
以下是文檔官方描述,文檔恐懼的小夥伴慎入,不喜歡讀文檔的小夥伴可跳過直接看例子學習
inspect.getclasstree(classes, unique=False)
該函數文檔中的解釋是:Arrange the given list of classes into a hierarchy of nested lists,翻譯過來就是將給定的類列表排列成嵌套列表的層次結構。
在出現嵌套列表的地方,它包含從緊靠列表前面的類派生的類,返回的每個條目都是一個2元組,包含一個類及其基類的元組。這是講了返回值
參數「unique」默認為False,如果為True,則給定列表中每個類的返回結構中只會出現一個條目。否則,使用多重繼承的類及其子代將多次出現。這裡講參數
怎麼樣?是不是很複雜,其實它就是根據一個給定的類或者基類,創建一個類似樹的數據結構,返回列表中,各個元素可能是一個包含類及其基類的元組,也可能是另一個包含子類元組的列表。
上面講了一串東西,很無聊,不是嗎?
再簡單點理解,就是用它可以知道類的層次結構和繼承順序。
對著一個簡單的例子來理解下,千萬別走開哦……
定義示例類
首先定義四個相互繼承的類A、B、C、D
class A(object):
pass
class B(A):
pass
class C(B):
pass
class D(C, A):
pass
獲取類的層次結構
例子中繼承順序是這樣的:B繼承自A,C又繼承自B,D有兩個父類C、A
我們使用上面的方法看下類A、B、C、D的層次結構。
import inspect
from pprint import pprint
pprint(inspect.getclasstree([A,B,C,D]))
>>>
[(<class 'object'>, ()),
[(<class '__main__.A'>, (<class 'object'>,)),
[(<class '__main__.B'>, (<class '__main__.A'>,)),
[(<class '__main__.C'>, (<class '__main__.B'>,)),
[(<class '__main__.D'>, (<class '__main__.C'>, <class '__main__.A'>))]],
(<class '__main__.D'>, (<class '__main__.C'>, <class '__main__.A'>))]]]
好吧,貌似把本來不算複雜的問題被我們搞複雜了
但它確實列印出來了類的層次結構。我們定義一個函數,將上面的結果處理下
def print_class_tree(tree, indent=-1):
if isinstance(tree, list):
for node in tree:
print(print_class_tree(node, indent + 1))
else:
print("\t" * indent + tree[0].__name__)
return ""
然後來看下編譯器中返回的結果
成功獲取類的層次結構。然後我們使用參數unique=True看下結果。
可以看出,子類D對於A的繼承沒有顯示出來,但這樣貌似更加直觀。但它的代價是減少了部分繼承內容。
多重繼承的順序
我們知道,對於一個多重繼承的類(有多個父類),如果其父類中都定義了一個重名方法,那麼,子類使用哪個父類的同名方法呢?這就牽扯到繼承順序的問題?
方法一:使用類名.__mro__或者直接使用類名.mro()方法獲取
如
print(D.mro()) 或者print(D.__mro__)
>>>(<class '__main__.D'>, <class '__main__.C'>, <class '__main__.B'>, <class '__main__.A'>, <class 'object'>)
其實,細心的小夥伴肯定能發現,D.mro()返回的是個列表list類型,而D.__mro__返回的則是個元組tuple類型。
方法二:使用inspect.getmro()方法獲取,示例如下:
print(inspect.getmro(D))
>>>(<class '__main__.D'>, <class '__main__.C'>, <class '__main__.B'>, <class '__main__.A'>, <class 'object'>)
結果完全相同,使用inspect.getmro(D)方法等同於D.__mro__。
獲得清晰的繼承關係
對於這個問題,直接遍曆元組,獲取逐個獲取類名即可解決
for item in inspect.getmro(D):
print("{}".format(item.__name__))
輸出結果如下
>>>
D
C
B
A
object
清晰反映了類的繼承順序。
好了,今天的內容就到這裡了,喜歡的小夥伴們點個讚唄!
對於Python類的繼承順序,到底是「深度優先」還是「廣度優先」,歡迎大家留言討論。
轉載請註明出處,百家號:Python高手養成