1

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'
4

2 に答える 2

1

jsonpickle 内での型の進化または型の移行はサポートされていません。

最善json.loadsの方法は、データの JSON 表現をリスト / 辞書 / 文字列 / 数値の基本的な Python 構造に ( 経由で) ロードすることです。この Python 表現をトラバースし、空/デフォルトbキーを追加します。次に、JSON を で再保存しますjson.dumps

次に、jsonpickle を使用して、変更されたバージョンのデータをロードできます。

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

オブジェクト モデルがより複雑な場合、これは明らかにより複雑になりますが、py/object キーをチェックして、オブジェクトを変更する必要があるかどうかを確認できます。

于 2012-10-27T00:48:40.900 に答える
0

バージョニングの問題のため、jsonpickle だけではオブジェクトを永続化するのに十分ではありません。また、古いバージョンを読み取るときにデータを後付け (クリーンアップ) できるように、JSON 出力にバージョン識別子を保持する必要があります。

そうは言っても、生活を楽にするためにできることがあります。オブジェクトのiterと組み合わせて json.dumps の default=dict パラメータを使用でき ます。これにより、オブジェクトを辞書として永続化できます。それを読み込むと、 **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__ ctor で初期化コードは実行されません。これは次のようになります。

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'
于 2016-01-27T00:28:06.920 に答える