標籤:

Python中list與collections.abc.Sequence是什麼關係?

看上去Sequence並不是list的父類(也許是?但為什麼mro里沒有)

為什麼[]卻又是這兩個玩意兒的instance呢?求解。。list和Sequence到底是什麼關係

&>&>&> type([])

&

&>&>&> isinstance([],list)

True

&>&>&> isinstance([],Sequence)

True

&>&>&> list.mro()

[&, &]


首先list和Sequence的關係當然不是isinstance,而是應該用issubclass來判斷。

但是,list的__mro__當中也的確沒有Sequence,但卻有issubclass(list, Sequence) == True

這是一個Python獨有的OOP機制叫做subclass/subinstance hook,詳細內容可以參見官方文檔

3. Data model - Python 3.6.4 documentation

簡單來說,isinstance和issubclass兩個內置函數有個hook掛載點,當需要判斷的類型/父類的metaclass(注意,必須是metaclass上定義的,在class本身定義了這兩個函數不生效)包含了__instancecheck__和/或者 __subclasscheck__兩個magic函數的時候,會使用這兩個定義的函數來做isinstance和issubclass的檢測,從而覆蓋默認的__mro__的機制。

從這個技術就誕生了標準庫的abc庫,它的主要目標是將一些傳統上使用duck type檢測(比如檢查有沒有特定的介面)的代碼都統一到了isinstance和issubclass上,技術就是使用上面的兩個方法。

那麼對於Sequence來說,它使用abc中的metaclass,這個metaclass通過兩種不同的技術來判斷是否為subclass:

  1. 應用__subclasshook__的方法,例如Iterable,任何定義了__iter__的類都會判斷得到issubclass(MyClass, Iterable) == True
  2. 應用register,可以將其他類註冊為該abc的子類,從而有issubclass(RegisteredClass, Sequence) == True

list就是通過register註冊到了Sequence的一個子類MutableSequence上,從而成為Sequence的虛擬子類,即便它的__mro__中沒有Sequence和MutableSequence。

題外話,這兩種技術加上傳統的__mro__判斷在abc的實現中是交叉使用的,很有趣,比如說Iterable的判斷,正常來說是通過有沒有__iter__判斷的,但是Iterable的直接子類(即繼承於Iterable的類,包括其它abc)的機制也會產生影響,當前一個判斷不為True的時候,會繼續判斷該類和Iterable的直接子類的關係。我們知道str其實是沒有__iter__方法的,只有__getitem__,但Sequence是Iterable的子類,str又通過register機製成為了Sequence的子類,這樣判斷issubclass(str, Iterable)的時候,首先通過__subclasshook__判斷失敗,接著依次查找Iterable的子類,發現它是Sequence的子類,最終返回True,充分保證了子類的子類仍然是子類的OOP原則。list也是通過註冊到MutableSequence而成為Sequence的子類的。


推薦閱讀:

如何優雅的「輪帶逛」初級篇——獲取單張圖片
為什麼 Python 不用 C++ 實現?
看看黃哥是怎麼解決問題的,網友答疑對話錄
Python從零開始系列連載(23)——Python特色數據類型(字典)(下)
seaborn可視化之heatmap & time series & regression

TAG:Python |