Effective Python 读书笔记: 第34条: 用元类来注册子类

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

import json

'''
第34条: 用元类来注册子类

关键:
1 元类
作用: 在程序中自动注册类型,对于需要反向查询的场合有用。
    可以在简单的标示符与对应的类之间建立映射关系。
应用场景:
1) 将python对象表示为JSON格式的序列化数据,即
将指定对象转换成JSON字符串。
2) 开发者继承某个类的时候,程序自动调用registerCLass方法
,并将新的子类注册好。
原因: 定义完子类的class语句体后,元类可以拦截这个新的子类,
就可以注册新的类型

2 元类中注册子类的用法
示例:
class Meta(type):
    def __new__(meta, name, bases, class_dict):
        cls = type.__new__(meta, name, bases, class_dict)
        # 获取新的类后,注册该类
        registerClass(cls)
        return cls


class RegisteredSerializable(BetterSerializable):
    __metaclass__ = Meta


class Vector3D(RegisteredSerializable):
    def __init__(self, x, y, z):
        super(Vector3D, self).__init__(
            x, y, z
        )
        self.x = x
        self.y = y
        self.z = z


def useMetaclass2():
    v3 = Vector3D(1, 2, 3)
    print "Before: {value}".format(
        value=v3
    )
    data = v3.serialize()
    print "Serialized: {value}".format(
        value=data
    )
    after = deserialize(data)
    print "After: {value}, type: {mytype}".format(
        value=after,
        mytype=type(after)
    )
        
分析:
1) 元类必须继承万物之祖 type
2)注意元类的type.__new__(meta, name, bases, class_dict)返回的就是我们的类这个类型

3 总结
1) 类的注册是很有用的模式, 
2) 设置元类中可以返回获取的新的类的时候,进行注册
(实际就是设置: <类名, 类> 的字典)
从基类中指定元类为刚才编写的元类,那么子类继承基类的时候,
就可以自动注册子类了


参考:
Effectiv Python 编写高质量Python代码的59个有效方法
'''
class Serializable(object):
    def __init__(self, *args):
        self.args = args

    def serialize(self):
        return json.dumps({"args": self.args})


class Point2D(Serializable):
    def __init__(self, x, y):
        super(Point2D, self).__init__(x, y)
        self.x = x
        self.y = y

    def repr(self):
        return "Point2D(%d, %d)" % (self.x, self.y)


class Deserializable(Serializable):
    @classmethod
    def deserialize(cls, jsonData):
        params = json.loads(jsonData)
        return cls(*params['args'])


class BetterPoint2D(Deserializable):
    pass


class BetterSerializable(object):
    def __init__(self, *args):
        self.args = args

    def serialize(self):
        # 把序列化对象的类名写道JSON数据里面
        return json.dumps(
            {
                'class': self.__class__.__name__,
                'args': self.args
            }
        )

    def __repr__(self):
        return "args: {args}".format(args=self.args)

registry = {}

'''
建立: <类名,类>的映射,用于后续根据序列化的数据建立类的实例
'''
def registerClass(targetClass):
    registry[targetClass.__name__] = targetClass


def deserialize(data):
    params = json.loads(data)
    name = params['class']
    targetClass = registry[name]
    return targetClass(*params['args'])


class EvenBetterPoint2D(BetterSerializable):
    def __init__(self, x, y):
        super(EvenBetterPoint2D, self).__init__(x, y)
        self.x = x
        self.y = y


def useMetaclass():
    point = Point2D(5, 3)
    print "Object: {point}".format(point=point)
    print "Serialized: {point}".format(point=point.serialize())
    point = BetterPoint2D(5, 3)
    print "Before: {value}".format(value=point)
    data = point.serialize()
    print "Serialized: {value}".format(
        value=data
    )
    after = BetterPoint2D.deserialize(data)
    print "After: {value}".format(
        value=after
    )
    print "##################### registry class"
    registerClass(EvenBetterPoint2D)
    point = EvenBetterPoint2D(5, 3)
    print "Before:  {point}".format(point=point)
    data = point.serialize()
    print "Serialized: {data}".format(data=data)
    after = deserialize(data)
    print "After: {after}, type: {value}".format(
        after=after, value=type(after))


'''
注意: 元类必须继承自万物之祖type
'''
class Meta(type):
    def __new__(meta, name, bases, class_dict):
        cls = type.__new__(meta, name, bases, class_dict)
        # 获取新的类后,注册该类
        registerClass(cls)
        return cls


class RegisteredSerializable(BetterSerializable):
    __metaclass__ = Meta


class Vector3D(RegisteredSerializable):
    def __init__(self, x, y, z):
        super(Vector3D, self).__init__(
            x, y, z
        )
        self.x = x
        self.y = y
        self.z = z


def useMetaclass2():
    v3 = Vector3D(1, 2, 3)
    print "Before: {value}".format(
        value=v3
    )
    data = v3.serialize()
    print "Serialized: {value}".format(
        value=data
    )
    after = deserialize(data)
    print "After: {value}, type: {mytype}".format(
        value=after,
        mytype=type(after)
    )


def process():
    useMetaclass2()


if __name__ == "__main__":
    process() 

猜你喜欢

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