Шаблон наследования Python - как справиться с десериализацией - PullRequest
0 голосов
/ 29 июня 2018

Скажем, мы хотим сериализовать B ниже:

import json
class A:
    def __init__(self):
        self.a = 1
    @classmethod
    def serialize(cls, t):
        with open('temp_A.json', 'wb') as f:
            json.dump({'a':t.a}, f)
    @classmethod
    def deserialize(cls):
        with open('temp_A.json', 'rb') as f:
            d = json.load(f)
            obj = A()
            obj.a = d['a']
            return obj

class B(A):
    def __init__(self):
        super(B, self).__init__()
        self.b = 2
    @classmethod
    def serialize(cls, t):
        with open('temp_B.json', 'wb') as f:
            json.dump({'b':t.b}, f)
    @classmethod
    def deserialize(cls):
        with open('temp_B.json', 'rb') as f:
            d = json.load(f)
            obj = B()
            obj.b = d['b']
            a = A.deserialize()
            #### IMPORTANT: doesn't work
            super(B, b) = a
            ####
            return b

Если этот шаблон сериализации ужасен и у вас есть альтернативы, пожалуйста, дайте мне знать. Однако на текущем этапе я не уверен, как переназначить переменные-члены суперкласса как атрибуты a (так как состояние a может отличаться от исходного построения). Я знаю, что могу сделать что-то вроде super(B,b).__dict__ = a.__dict__, но это нехорошо. Что такое Python-идиоматический способ выполнения чего-то подобного?

1 Ответ

0 голосов
/ 29 июня 2018

Заимствование уловов у pickle:

import json
class A:
    def __init__(self):
        self.a = 1

    def __getstate__(self):
        return {'a': self.a}

    def __setstate__(self, state):
        '''Accepts a json/dict, sets member attributes accordingly'''
        self.a = state['a']

    def serialize(self):
        return json.dumps(self.__getstate__())

    @classmethod
    def deserialize(cls, json_str):
        d = json.loads(json_str)
        obj = cls()
        obj.__setstate__(d)
        return obj

class B(A):
    def __init__(self):
        super(B, self).__init__()
        self.b = 2

    def __setstate__(self, state):
        '''Accepts a json/dict, sets member attributes accordingly'''
        super().__setstate__(state)
        self.b = state['b']

    def __getstate__(self):
        state = super().__getstate__()
        state.update({'b': self.b})  # or state['b'] = self.b
        return state

    def serialize(self):
        return json.dumps(self.__getstate__())

    @classmethod
    def deserialize(cls, json_str):
        d = json.loads(json_str)
        obj = cls()
        obj.__setstate__(d)
        return obj


# Test A roundtrip
a1 = A()
a1_str = a1.serialize()
print(a1_str)               # {"a": 1}

a2 = A.deserialize(a1_str)
a2_str = a2.serialize()
print(a2_str)               # {"a": 1}

print(a1_str == a2_str)     # True

# Test B roundtrip
b1 = B()
b1_str = b1.serialize()
print(b1_str)               # {"a": 1, "b": 2}

b2 = B.deserialize(b1_str)
b2_str = b2.serialize()
print(b2_str)               # {"a": 1, "b": 2}

print(b1_str == b2_str)     # True

Здесь есть несколько других изменений, таких как не жесткое кодирование имени класса в методе deserialize() class, сериализация в строку вместо файла (для тестирования), использование непротиворечивого dumps / loads вместо одного из каждого.

...