使用jsonpickle(python)进行类型演化

时间:2012-10-26 11:15:47

标签: python schema jsonpickle

在jsonpickle中是否有任何支持?

E.g。我存储和对象,他们修改其架构,然后尝试加载它。

以下更改,例如(属性添加)

import jsonpickle

class Stam(object):

   def __init__(self, a):
     self.a = a

   def __str__(self):
     return '%s with a=%s' % (self.__class__.__name__, str(self.a))


js = jsonpickle.encode(Stam(123))
print 'encoded:', js

class Stam(object):

   def __init__(self, a, b):
     self.a = a
     self.b = b

   def __str__(self):
     return '%s with a=%s, b=%s' % (self.__class__.__name__, str(self.a), str(self.b))

s=jsonpickle.decode(js)
print 'decoded:', s

产生错误:

encoded: {"py/object": "__main__.Stam", "a": 123}
decoded: Traceback (most recent call last):
  File "C:\gae\google\appengine\ext\admin\__init__.py", line 317, in post
    exec(compiled_code, globals())
  File "<string>", line 25, in <module>
  File "<string>", line 22, in __str__
AttributeError: 'Stam' object has no attribute 'b'

2 个答案:

答案 0 :(得分:1)

jsonpickle中不支持类型演变或类型迁移。

您最好的做法是将数据的JSON表示加载(通过json.loads)到list / dicts / strings / numbers的基本Python结构中。遍历此Python表示,添加空/默认b键。然后通过json.dumps重新保存JSON。

然后,您可以使用jsonpickle加载修改后的数据版本。

temp = json.loads(js)
temp['b'] = None
js = json.dumps(temp)
jsonpickle.decode(js)

如果您的对象模型更复杂,这显然会变得更复杂,但您可以检查py / object键以查看是否需要修改对象。

答案 1 :(得分:0)

由于版本控制问题,单独使用jsonpickle是不够的 持久的物体。您还需要保留版本标识符 JSON输出,以便您可以在需要时对数据进行改造(清理) 阅读旧版本。

说到这里,你可以做一些让生活更轻松的事情。您 可以使用json.dumps的default = dict参数 你对象上的 iter 。这将让你坚持你的对象 字典。然后,当你阅读它时,你可以使用** dict运算符和 从JSON字典重新实例化对象的关键字参数。

这允许您读入持久对象并提供 初始化任何新属性。例如,如果我们从一个开始 具有val1属性并保持它的类,然后将类展开为 具有val2属性并从持久状态恢复:

import json

class Stam( object ) :
    val1 = None
    def __init__( self, val1=None ) :
        self.val1 = val1

    def __iter__( self ) : return {
        'val1':self.val1
    }.iteritems()

obj1 = Stam( val1='a' )
persisted = json.dumps( obj1, default=dict )

class Stam( object ) :
    val1 = None
    val2 = None
    def __init__( self, val1=None, val2='b' ) :
        self.val1 = val1
        self.val2 = val2

    def __iter__( self ) : return {
        'val1':self.val1,
        'val2':self.val2
    }.iteritems()

obj2 = json.loads( persisted, object_hook=lambda d: Stam(**d) )
assert obj2.val1 == 'a'
assert obj2.val2 == 'b'

当然,我们也可以使用jsonpickle并跳过__iter__和 额外的json参数,因为jsonpickle将忽略缺失 属性。因此任何新的val2都将具有静态类初始化 提供,但它不会运行__init__中的初始化代码 构造函数。这将成为:

import jsonpickle

class Stam( object ) :
    val1 = None
    def __init__( self, val1 ) :
        self.val1 = val1

obj1 = Stam( 'a' )
persisted = jsonpickle.encode( obj1 )

class Stam( object ) :
    val1 = None
    val2 = 'b'
    def __init__( self, val1, val2 ) :
        self.val1 = val1
        self.val2 = val2

obj2 = jsonpickle.decode( persisted )
assert obj2.val1 == 'a'
assert obj2.val2 == 'b'