almost 3 years ago

Register Class Existence with Metaclasses

這個條款講得是另一種 metaclasses 用途。

下面的程式碼將 class 名稱記錄在 json.dumps 出來的 json string 裡頭,這樣就可有個通用的 deserialize() 產生對應的 instance。

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):
        return '%s(%s)' % (
            self.__class__.__name__,
            ', '.join(str(x) for x in self.args))


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(*params['args'])

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

麻煩的地方在於每次新增 BetterSerializable 的子類就要呼叫 register_class() ,容易忘記。

register_class(EvenBetterPoint2D)

point = EvenBetterPoint2D(5, 3)
print('Before:    ', point)
data = point.serialize()
print('Serialized:', data)
after = deserialize(data)
print('After:     ', after)

可以用 metaclass 解決

class Meta(type):
    def __new__(meta, name, bases, class_dict):
        cls = type.__new__(meta, name, bases, class_dict)
        register_class(cls)
        return cls
← Effective Python 心得筆記: Item 33 Effective Python 心得筆記: Item 35 →
 
comments powered by Disqus