使用Python內置的issubclass方法很方便的檢測一個類是否是另一個類的子類。
這個是issubclass的文檔:
issubclass(class, classinfo)
Return true if class is a subclass (direct, indirect or virtual) of classinfo. A class is considered a subclass of itself. classinfo may be a tuple of class objects, in which case every entry in classinfo will be checked. In any other case, a TypeError exception is raised.
一個類的子類可以是直接的、間接的、或者是虛擬的。
issubclass的第二個參數classinfo可以是一個類對象或者包含類對象的tuple(只要其中一個檢測成功即返回True)。
一些使用示例:
>>> class A(object): ... pass ... >>> class B(A): ... pass ... >>> class C(B, A): ... pass ... >>> class D(C): ... pass ... >>> issubclass(D, D), issubclass(D, C), issubclass(D, B), issubclass(D, A), issubclass(D, object) (True, True, True, True, True) >>> D.__bases__ (,) >>> D.__mro__ ( , , , , )
D是D的子類,D定義時的基類是C,所以D是C的子類,而且D是B,A,object的間接子類。
__mro__是類屬性, 在類定義完畢Python解析器便通過一種C3算法將所有的父類以method resolution order的順序保存到一個元組里, 成為類的屬性。
所以issubclass可以這樣簡單的實現:
def issubclass(cls, classinfo): if classinfo in cls.__mro__: return True return False
Python的issubclass是內置函數(一般是C實現),實際上要復雜很多,要檢測參數類型,如第一個參數必須是type類型,第二個參數是type類型或者tuple類型。還要考慮該類是否是虛擬的子類,以及子類的子類。
例如:
>>> from collections import abc >>> class E: ... def __len__(self): ... return 1 ... >>> issubclass(E, abc.Sized) True >>> E.__mro__ (, ) >>> class F: ... pass ... >>> issubclass(F, abc.Sized) False >>> abc.Sized.register(F) >>> issubclass(F, abc.Sized) True
Python是動態類型語言,長久以來使用Duck type(鴨子類型)形式編程,不管對象是什么類型,只要實現了所需要的方法。
現在有了ABCs, 可以用于判斷某個類或者某個對象是不是ABCs的子類或者實例,但這個類并不需要顯示的繼承于ABCs, 因為python內置的ABCs有一種注冊機制可將一個類注冊為它的子類。如上例子的register方法。
還有一種機制是可以定制一個__subclasshook__方法,將某種類型的類認定為子類。
如abc.Sized的__subclasshook__是這樣子的:
@classmethod def __subclasshook__(cls, C): if cls is Sized: if any("__len__" in B.__dict__ for B in C.__mro__): return True return NotImplemented
所以有__len__方法的E類是abc.Sized的子類, 這個__subclasshook__方法是通過__subclasscheck__方法調用的,這個__subclasscheck__是每一個ABC類都有的方法,在ABCMeta類(其他ABC類都繼承于它)實現。
現在的issubclass函數的實現,會先判斷classinfo是否有__subclasscheck__方法,如果有此方法,則判斷子類的邏輯由該方法返回,即覆蓋issubclass的實現(CPython)。
__subclasscheck__會分幾個步驟進行判斷:
- 調用__subclasshook__方法,如果有方法定義
- 檢查自己是否在待檢測類的__mro__列表里
- 遞歸檢查待檢測類是否是在注冊子類(內置_abc_registry列表屬性)
- 遞歸檢查待檢測類是否是自己子類的子類
具體源碼在: https://github.com/python/cpython/blob/3.6/Lib/abc.py#L194-L231
相關的CPython實現在: https://github.com/python/cpython/blob/0ccc0f6c7495be9043300e22d8f38e6d65e8884f/Objects/abstract.c#L2223
而基本上isinstance(object, classinfo)方法的實現只需要調用issubclass(type(object), classinfo)
參考:
29.7. abc ― Abstract Base Classes : https://docs.python.org/3/library/abc.html
PEP 3119 ?C Introducing Abstract Base Classes: https://www.python.org/dev/peps/pep-3119/
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持腳本之家。
更多文章、技術交流、商務合作、聯系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號聯系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元
