第33/34條 用元類驗證和註冊子類

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__方法給對象屬性進行賦值。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章