26. 只在混合實用類(MIX-IN UTILITY CLASSES)中使用多繼承

原文標題:USE MULTIPLE INHERITANCE ONLY FOR MIX-IN UTILITY CLASSES

我對原文中的mix-in理解的很不好,如果哪位朋友對這個概念比較懂,可以給我留言,謝謝。

Python作為一款面向對象編程語言,提供了很多內嵌方法使得多繼承很容易管理。但是仍然不建議使用多繼承。

如果你想要在多繼承的同時還能保證代碼的方便性和封裝性,可以考慮使用mix-in。Mix-in是一個非常小的類,它只定義了一系列類需要提供的方法(A mix-in is a small class that only defines a set of additional methods that a class should provide)。Mix-in類既不定義自己的實體屬性也不要求自己的構造方法__init__被調用。

由於使用Python可以很容易的檢查任何對象的狀態,所以編寫mix-in很容易。動態檢查使得你可以在mix-in中編寫一次通用方法,在其它類中多次使用。通過對mix-in的組合與封層可以最小化代碼重複並且最大化代碼複用。

例如,假設你希望能夠將Python對象從其內存表示形式轉換為可以序列化的字典。那麼為什麼不考慮將這個功能寫成一個通用方法呢?這樣你就可以在任意類中使用它了。

下面我定義了一個mix-in,這個min-in包含了一個方法可以實現以上需求,那麼所有繼承自這個類的類都有了這個功能:

26. 只在混合實用類(MIX-IN UTILITY CLASSES)中使用多繼承

代碼的具體實現主要依賴動態屬性訪問 hasattr,動態類型檢查 isinstance,訪問實例字典 __dict__。

26. 只在混合實用類(MIX-IN UTILITY CLASSES)中使用多繼承

下面我定義了一個類,通過使用上面的mix-in可以將一個字典表示為二叉樹:

26. 只在混合實用類(MIX-IN UTILITY CLASSES)中使用多繼承

此時將很多Python對象轉換為字典就變得非常容易了:

26. 只在混合實用類(MIX-IN UTILITY CLASSES)中使用多繼承

mix-in最棒得地方在於,你可以將通用方法做成可插入的(pluggable),所有代碼行為可以在需要的時候被重新。例如,下面定義了一個新類,它是BinaryTree的子類,它包含了一個parent屬性。這種循環將會導致ToDictMixin.to_dict陷入死循環(This circular reference would cause the default implementation of ToDictMixin.to_dict to loop forever):

26. 只在混合實用類(MIX-IN UTILITY CLASSES)中使用多繼承

解決方法就是在BinaryTreeWithParent中重寫ToDictMixin._traverse方法,阻止循環的產生。在此,我更新了_traverse方法使它不處理parent,而僅僅插入數值(I override the _traverse method to not traverse the parent and just insert its numerical value):

26. 只在混合實用類(MIX-IN UTILITY CLASSES)中使用多繼承

這時再調用BinaryTreeWithParent.to_dict就不會有錯了。

26. 只在混合實用類(MIX-IN UTILITY CLASSES)中使用多繼承

通過定義BinaryTreeWithParent._traverse,所有包含BinaryTreeWithParent 屬性的類都自動擁有了ToDictMixin的能力,例如:

26. 只在混合實用類(MIX-IN UTILITY CLASSES)中使用多繼承

Mix-in還可以被組合起來使用,例如你希望創建一個mix-in,這個mix-in可以用來對任意類進行JSON序列化。在完成這個代碼的時候,你可以假設這個類提供了一個to_dict方法:

26. 只在混合實用類(MIX-IN UTILITY CLASSES)中使用多繼承

注意JsonMixin 是如何同時定義類方法和實例方法的,Mix-in允許同時添加這兩種行為。在本例中唯一的要求就是JsonMixin 包含to_dict方法同時__init__方法接收關鍵字參數。

mix-in使得創建實用類進行JSON序列化反序列化變得很容易。例如下面用於表示數據的類:

26. 只在混合實用類(MIX-IN UTILITY CLASSES)中使用多繼承

下面測試一下序列化和反序列化:

26. 只在混合實用類(MIX-IN UTILITY CLASSES)中使用多繼承


分享到:


相關文章: