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() 

 

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