Effective Python 读书笔记: 第33条: 用元类来验证子类

# -*- encoding: utf-8 -*-

import os

'''
第33条: 用元类来验证子类

关键:
1 元类
作用: 验证某个类定义是否正确
原理: 定义新的类时,它会运行验证代码,确保新类符合规范
定义元类: 定义元类,需要从type中继承
对于使用该元类的其他类来说,会把这些类的class语句提中的内容发送给元类的
__new__方法。

2 元类的特点与引用场景
特点: 元类可以获知那个类的名称,继承的父类,以及定义在class与具体中的全部类属性
应用场景: 为了确保类的参数有效,可以把验证逻辑添加到Meta.__new__方法中
例如需要用类表示多边形,定义特殊验证类作为多边形的基类,把这个验证类当成自己的元类
注意: 元类中编写的验证逻辑时针对该基类的子类,而非基类本身

3 元类用法示例:
1) 元类继承自type,包含: 元数据,使用元类的那个类的名称,使用元类的那个类的父类,使用元类的那个类的类属性
2) 返回时,返回  type.__new__(meta, name, bases, class_dict)
3) 使用元类的类在类中定义一个类属性如下:
__metaclass__ = MyMetaClass

样例:
class ValidatePolygon(type):
    def __new__(meta, name, bases, class_dict):
        # 不要验证基类本身,而是验证基类的子类
        if bases != (object,):
            if class_dict['sides'] < 3:
                raise ValueError('Polygons need more than three sides')
        return type.__new__(meta, name, bases, class_dict)


class Polygon(object):
    __metaclass__ = ValidatePolygon

    @classmethod
    def interiorAngles(cls):
        return (cls.sides - 2) * 180


class Triangle(Polygon):
    sides = 3

4 总结
元类可以在生成子类对象之前验证子类的定义是否符合要求
子类的class语句处理完成后,会调用其元类的__new__方法

参考:
Effectiv Python 编写高质量Python代码的59个有效方法
'''

class Meta(type):
    def __new__(meta, name, bases, class_dict):
        print "meta: {meta}, name: {name}, bases: {bases}, class_dict: {class_dict}".format(
            meta=meta,
            name=name,
            bases=bases,
            class_dict=class_dict
        )
        return type.__new__(meta, name, bases, class_dict)


class MyClass(object):
    __metaclass__ = Meta

    stuff = 123

    def foo(self):
        pass


class ValidatePolygon(type):
    def __new__(meta, name, bases, class_dict):
        # 不要验证基类本身,而是验证基类的子类
        if bases != (object,):
            if class_dict['sides'] < 3:
                raise ValueError('Polygons need more than three sides')
        return type.__new__(meta, name, bases, class_dict)


class Polygon(object):
    __metaclass__ = ValidatePolygon

    @classmethod
    def interiorAngles(cls):
        return (cls.sides - 2) * 180


class Triangle(Polygon):
    sides = 3

print "Before class"
class Line(Polygon):
    print "Before sides"
    sides = 1
    print "After sides"
print "After class"


def useMetaClass():
    myClass = MyClass()


def process():
    useMetaClass()


if __name__ == "__main__":
    process() 

猜你喜欢

转载自blog.csdn.net/qingyuanluofeng/article/details/88933830