由于类型演变,jsonpickle强制使用__dict__

时间:2015-01-21 17:42:28

标签: python json serialization jsonpickle

此问题与type evolution with jsonpickle (python)

有关

当前状态说明:

我需要在python中使用jsonpickle将对象存储到JSON文件。

对象类CarState由另一个软件组件的脚本生成,因此我无法更改类本身。此脚本自动为jsonpickle用于序列化对象的类生成__getstate____setstate__方法。 __getstate__只返回每个成员变量的值列表,没有字段名称。 因此,jsonpickle不会存储字段名称,只会存储JSON数据中的值(请参阅下面的代码示例)

问题:

让我们说我的程序需要通过附加字段(CarState)扩展新版本(版本2)的类CarStateNewVersion。现在,如果它从版本1加载JSON数据,则数据不会分配到正确的字段。

这是一个展示问题的示例代码。 类CarState由脚本生成,并在此处简化以显示问题。在版本2中,我使用新字段更新了类CarState(在代码剪辑中插入CarStateNewVersion以保持简单)

#!/usr/bin/env python
import jsonpickle as jp

# Class using slots and implementing the __getstate__ method
# Let's say this is in program version 1
class CarState(object):
    __slots__ = ['company','type']
    _slot_types = ['string','string']

    def __init__(self):
        self.company = ""
        self.type = ""

    def __getstate__(self):
        return [getattr(self, x) for x in self.__slots__]

    def __setstate__(self, state):
        for x, val in zip(self.__slots__, state):
            setattr(self, x, val)

# Class using slots and implementing the __getstate__ method
# For program version 2 a new field 'year' is needed           
class CarStateNewVersion(object):
    __slots__ = ['company','year','type']
    _slot_types = ['string','string','string']

    def __init__(self):
        self.company = ""
        self.type = ""
        self.year = "1900"

    def __getstate__(self):
        return [getattr(self, x) for x in self.__slots__]

    def __setstate__(self, state):
        for x, val in zip(self.__slots__, state):
            setattr(self, x, val)

# Class using slots without the __getstate__ method
# Let's say this is in program version 1            
class CarDict(object):
    __slots__ = ['company','type']
    _slot_types = ['string','string']

    def __init__(self):
        self.company = ""
        self.type = ""

# Class using slots without the __getstate__ method
# For program version 2 a new field 'year' is needed      
class CarDictNewVersion(object):
    __slots__ = ['company','year','type']
    _slot_types = ['string','string','string']

    def __init__(self):
        self.company = ""
        self.type = ""
        self.year = "1900"



if __name__ == "__main__":

    # Version 1 stores the data
    carDict = CarDict()
    carDict.company = "Ford"
    carDict.type = "Mustang"
    print jp.encode(carDict)
    # {"py/object": "__main__.CarDict", "company": "Ford", "type": "Mustang"}

    # Now version 2 tries to load the data
    carDictNewVersion = jp.decode('{"py/object": "__main__.CarDictNewVersion", "company": "Ford", "type": "Mustang"}')
    # OK!
    # carDictNewVersion.company = Ford
    # carDictNewVersion.year = undefined
    # carDictNewVersion.type = Mustang


    # Version 1 stores the data
    carState = CarState()
    carState.company = "Ford"
    carState.type = "Mustang"
    print jp.encode(carState)
    # {"py/object": "__main__.CarState", "py/state": ["Ford", "Mustang"]}

    # Now version 2 tries to load the data    
    carStateNewVersion = jp.decode('{"py/object": "__main__.CarStateNewVersion", "py/state": ["Ford", "Mustang"]}')
    # !!!! ERROR !!!!
    # carDictNewVersion.company = Ford
    # carDictNewVersion.year = Mustang
    # carDictNewVersion.type = undefined
    try:
        carDictNewVersion.year
    except:
        carDictNewVersion.year = 1900

正如您在CarDictCarDictNewVersion课程中看到的那样,如果__getstate__未实施,则新添加的字段没有问题,因为JSON文本还包含字段名称。

问题:

是否有可能告诉jsonpickle不使用__getstate__并使用__dict__代替在JSON数据中包含字段名称? 或者是否有其他可能以某种方式包括字段名称?

注意:我无法更改CarState类或包含__getstate__方法,因为它是通过其他软件组件的脚本生成的。 我只能在main方法中更改代码。

或者是否有另一个用于python的序列化工具,它创建了人类可读的输出并包含字段名称?


其他背景信息: 该类是使用ROS中的消息定义生成的,即genpy ,生成的类继承自实现Message的{​​{1}}类(参见https://github.com/ros/genpy/blob/indigo-devel/src/genpy/message.py#L308

1 个答案:

答案 0 :(得分:0)

子类CarState实现自己的pickle协议方法,或者用jsonpickle注册处理程序。