1.元類的定義
Python定義元類時,需要從type
類中繼承,然後重寫__new__
方法,便可以實現意想不到的功能。
class Meta(type):
def __new__(meta,name,bases,class_dict):
#...各種邏輯實現1
cls = type.__new__(meta,name,bases,class_dict)
#...各種邏輯實現2
return cls
class MyClass(object,metaclass=Meta):
stuff = 33
def foo(self):
pass
2.元類的本質
在Python當中萬物皆對象,我們用class
關鍵字定義的類本身也是一個對象,負責產生該對象的類稱之爲元類,元類可以簡稱爲類的類,元類的主要目的是爲了控制類的創建行爲。
-
type
是Python的一個內建元類,用來直接控制生成類,在Python中任何class
定義的類其實都是type
類實例化的結果。 -
只有繼承了
type
類才能稱之爲一個元類,否則就是一個普通的自定義類,自定義元類可以控制類的產生過程,類的產生過程其實就是元類的調用過程。
3.元類驗證子類
案例1:編寫一個多邊形類,當邊數小於3
時,其類報錯,實現其驗證邏輯。
class ValidatePolygon(type):
## __new__當中放入驗證邏輯
def __new__(meta,name,bases,class_dict):
if bases!=(object,): ##針對子類而不對基類
if class_dict['sides'] < 3:
raise ValueError('Polygons need 3+ sides')
return type.__new__(meta,name,bases,class_dict)
class Polygons(object,metaclass=ValidatePolygon):
sides = None
@classmethod
def interior_angles(cls):
return (cls.sides - 2) * 180
class Triangle(Polygons):
sides = 3
### 類設計報錯。
class Line(Polygons):
sides = 1
4.元類註冊子類
元類還有一個用途,就是在程序中自動註冊類型
。開發者每次從基類中繼承子類時,基類的元類都可以自動運行註冊代碼。
案例2:實現對象的序列化與反序列化
###建立類名與該類對象的映射關係,維護registry字典。
registry = {}
def register_class(target_class):
registry[target_class.__name__] = target_class
def deserialize(data):
params = json.loads(data)
name = params['class']
target_class = registry[name]
return target_class
class Meta(type):
def __new__(meta,name,bases,class_dict):
cls = type.__new__(meta,name,bases,class_dict)
register_class(cls) ##註冊子類
return cls
class BetterSerializable(object):
def __init__(self,*args):
self.args = args
def serialize(self):
return json.dumps({
'class':self.__class__.__name__,
'args':self.args,
}
)
def __repr__(self):
# ...
class RegisterSerializabel(BetterSerializable,metaclass=Meta):
pass
通過元類來實現類的註冊,可以確保所有的子類都不會遺漏,從而避免後續的錯誤。
5.總結
元類的各種操作可以實現類的驗證和註冊邏輯,均可以在元類的__new__
方法中實現,主要原因是當子類對象構建時,會先調用元類的__new__
方法,產生一個空對象,然後再調用子類的__init__
方法給對象屬性進行賦值。