第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__方法给对象属性进行赋值。

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