此问题与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
正如您在CarDict
和CarDictNewVersion
课程中看到的那样,如果__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)
答案 0 :(得分:0)
子类CarState
实现自己的pickle协议方法,或者用jsonpickle注册处理程序。