在讀werkzeug
和flask
的源碼中,經常能遇到類名中有mixin
這個東西。這個東西的用法讓我想到了java中的接口名有able
的用法。今天我就來看了看這個mixin
是什么東西。
學習了python的都知道,python是支持多繼承的,但是支不支持動態繼承性質呢?在程序運行過程中,重定義類的繼承,python是支持這種動態繼承性質的。這也就是python中的mixin
,在定義類過程中改變類的繼承順序,繼承類。當某個模塊不能修改時,通過mixin方式可以動態添加該類的方法,動態改變類的原有繼承體系。
Mixin
Mixin編程是一種開發模式,是一種將多個類中的功能單元的進行組合的利用的方式,這聽起來就像是有類的繼承機制就可以實現,然而這與傳統的類繼承有所不同。通常mixin並不作為任何類的基類,也不關心與什么類一起使用,而是在運行時動態的同其他零散的類一起組合使用。
使用mixin機制有如下好處:可以在不修改任何源代碼的情況下,對已有類進行擴展;可以保證組件的划分;可以根據需要,使用已有的功能進行組合,來實現“新”類;很好的避免了類繼承的局限性,因為新的業務需要可能就需要創建新的子類。
在舉例子之前,我們需要先熟悉幾個關鍵字:
-
__bases__
: 返回一個元組,該元組元素是類的基類,如:class a:
passprint(a.bases)
(<class 'object'>,)
可見a
類繼承了object
類 -
__mro__
:This attribute is a tuple of classes that are considered when looking for base classes during method resolution.
我的理解是 返回一個元組,該元組元素是該類的繼承的類,當查詢繼承的時候會按從左到右的順序。以剛剛的a
類為例:print(a.mro)
(<class 'main.a'>, <class 'object'>)
例子
在了解了以上的知識后,我來舉個例子
import types
def mixin(pyClass, pyMixinClass, key=0):
if key:
pyClass.__bases__ = (pyMixinClass,) + pyClass.__bases__
elif pyMixinClass not in pyClass.__bases__:
pyClass.__bases__ += (pyMixinClass,)
else:
pass
class test1:
def test(self):
print('In the test1 class!')
class testMixin:
def test(self):
print('In the testMixin class!')
class test2(test1, testMixin):
def test(self):
print('In the test2 class!')
class test0(test1):
pass
if __name__ == '__main__':
print(test0.__mro__) #繼承了test1,object
test_0 = test0()
test_0.test() #調用test1的方法
mixin(test0, testMixin, 1) #優先繼承testMixin類
test__0 = test0()
test__0.test() #由於優先繼承了testMixin類,所以調用testMixin類的方法
print(test0.__mro__)
print(test2.__mro__)
mixin(test2, testMixin)
print(test2.__mro__)
輸出結果:
(<class '__main__.test0'>, <class '__main__.test1'>, <class 'object'>)
In the test1 class!
In the testMixin class!
(<class '__main__.test0'>, <class '__main__.testMixin'>, <class '__main__.test1'>, <class 'object'>)
(<class '__main__.test2'>, <class '__main__.test1'>, <class '__main__.testMixin'>, <class 'object'>)
(<class '__main__.test2'>, <class '__main__.test1'>, <class '__main__.testMixin'>, <class 'object'>)
注意本例的mixin
方法,它的作用就是動態地給某個類(pyClass
)通過繼承的方式添加方法。
要注意:pyClass.__bases__ = (pyMixinClass,) + pyClass.__bases__
和pyClass.__bases__ += (pyMixinClass,)
二者的順序是不一樣的。 還是用例子說明:
a = (1,)
a = a + (2,)
print(a)
#輸出:(1,2)
a = (3,) + a
print(a)
#輸出:(3,1,2)
__bases__
返回的元組的元素順序不一樣會導致繼承的順序不一樣,類會優先繼承元組左邊的類