【问题标题】:type evolution with jsonpickle (python)使用 jsonpickle (python) 进行类型演化
【发布时间】:2012-10-16 15:49:14
【问题描述】:

jsonpickle 中是否对此有任何支持?

例如我存储和反对,他们修改其架构,然后尝试将其加载回来。

比如下面的变化,(属性加法)

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'

【问题讨论】:

    标签: python schema jsonpickle


    【解决方案1】:

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

    您最好的做法是将数据的 JSON 表示加载(通过json.loads)到列表/字典/字符串/数字的基本 Python 结构中。遍历这个 Python 表示,添加空/默认 b 键。然后通过json.dumps重新保存JSON。

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

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

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

    【讨论】:

      【解决方案2】:

      因为版本问题,单独使用 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'
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2015-10-25
        • 2021-04-03
        • 1970-01-01
        • 2021-03-05
        • 1970-01-01
        • 1970-01-01
        • 2014-09-26
        • 1970-01-01
        相关资源
        最近更新 更多