1

这个问题与 jsonpickle (python) 的类型演化有关

当前状态说明:

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

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

问题:

假设我的程序需要CarState通过附加字段 ( CarStateNewVersion) 为新版本(版本 2)扩展类。现在如果它从版本 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

正如你所看到的CarDictandCarDictNewVersion类,如果__getstate__没有实现,那么新添加的字段没有问题,因为JSON文本也包含字段名称。

问题:

是否有可能告诉 jsonpickle 不使用__getstate__并使用它__dict__来包含 JSON 数据中的字段名称?还是有另一种可能性以某种方式包含字段名称?

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

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


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

4

1 回答 1

0

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

于 2015-01-21T18:35:19.513 回答