python中元類在創建類和實例的作用
最近在研究backtrader
的底層源代碼,作者用類若干的類和元類,以前沒有接觸過元類,現在經過查了一些資料,知道了元類是創建類的類,可以用來控制類的創建和實例的創建過程,也可以隱性地繼承屬性和方法,元類的常見的應用有創建單類模式、ORM。
由於元類的理解比較抽象,可以用下面的代碼理解元類在創建類和實例時的作用,
- metaClass1: 繼承自
type
類的元類 - metaClass2: 繼承自
metaClass1
的元類 - A: 由
metaClass1
創建的類 - M:繼承自
A
的子類 - a: 類
A
的實例化對象 - m: 類
M
的實例化對象
class metaClass1(type):
def __new__(cls, clsname, bases, dct):
print("基於type的類metaClass1,....__new__")
return type.__new__(cls, clsname, bases, dct)
def __call__(self, *args, **kwargs):
print("基於type的類metaClass1,....__call__")
return super().__call__(*args, **kwargs)
class metaClass2(metaClass1):
def __new__(cls, clsname, bases, dct):
print("基於metaClass1的類metaClass2,....__new__")
return super().__new__(cls, clsname, bases, dct)
def __call__(self, *args, **kwargs):
print("基於metaClass1的類metaClass2,....__call__")
return super().__call__(*args, **kwargs)
print("創建類A-------")
class A(metaclass=metaClass2):
def __new__(cls, *agrs, **kwds):
inst = super().__new__(cls, *agrs, **kwds)
print("由metaClass2創建的類A,....__new__...正在創建類的實例")
return inst
def __init__(self):
print("由metaClass2創建的類A,....__init__...正在創建類的實例")
super().__init__()
class metaClass3(type):
def __new__(cls, clsname, bases, dct):
print("基於metaClass1的類metaClass2,....__call__")
return super().__new__(cls, clsname, bases, dct)
print('創建A的子類M-------')
class M(A, metaclass=type):
def __new__(cls, *agrs, **kwds):
print("類A的子類M,...__new__...正在創建類的實例")
return super().__new__(cls, *agrs, **kwds)
def __init__(self):
print("類A的子類M,...__init__...正在創建類的實例")
super().__init__()
print("創建A的實例--------")
a = A()
print("創建M的實例--------")
m = M()
輸出
創建類A-------
基於metaClass1的類metaClass2,....__new__
基於type的類metaClass1,....__new__
創建A的子類M-------
基於metaClass1的類metaClass2,....__new__
基於type的類metaClass1,....__new__
創建A的實例--------
基於metaClass1的類metaClass2,....__call__
基於type的類metaClass1,....__call__
由metaClass2創建的類A,....__new__...正在創建類的實例
由metaClass2創建的類A,....__init__...正在創建類的實例
創建M的實例--------
基於metaClass1的類metaClass2,....__call__
基於type的類metaClass1,....__call__
類A的子類M,...__new__...正在創建類的實例
由metaClass2創建的類A,....__new__...正在創建類的實例
類A的子類M,...__init__...正在創建類的實例
由metaClass2創建的類A,....__init__...正在創建類的實例
分析
這裏由兩條關係:父類-子類繼承關係、元類-類創建關係。
創建類
通過元類創建類時,子類M
不必另外聲明元類,因爲創建M
時,會默認調用父類A
的元類,如果設置metaclass
爲父類的元類外的別的元類,程序會出錯。用元類創建類時,依次調用元類的__new__
方法,該方法的參數分別爲:
cls
:類對象,類似class
中的self
clsname
: 類名,就像例子中的“A”、“M”bases
:類的父類dct
:類的屬性,是一個字典
通過這些參數可以看出,這是在得到類的屬性後纔會進入到元類中。
創建實例
創建實例涉及到類的__init__
、__new__
和元類的__call__
。
__call__
:首先調用父類的該方法,如果元類有繼承關係,先依次(子元類->父元類)調用完所有元類的__call__
方法,接着調用類的__new__
方法__new__
:調用完元類的__new__
方法後,接着調用類的__new__
,如果類有繼承關係,則依次(子類->父類)調用完所有類的__new__
方法__init__
:調用完所有類的__new__
方法後,接着調用類的__init__
,如果有類的繼承關係,則依次(子類->父類)調用所有類的__init__
方法