Because of the versioning problem, jsonpickle alone is not a sufficient for
persisting objects. You also need to keep a version identifier in
the JSON output so that you can retrofit (cleanup) the data when you are
reading an older version.
With that said, there are somethings you can do to make life easier. You
can use the default=dict parameter of json.dumps in conjunction with
iter on your object. This will let you persist your object as a
dictionary. Then when you read it in you can use the **dict operator and
key word arguments to re-instantiate your object from the JSON dictionary.
This allows you to read in your persisted objects and supply
initialization for any new attributes. For example if we start with an
class that has a val1 attribute and persist it, then expand the class to
have a val2 attribute and restore if from the persisted state:
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'
Of course, we could also use jsonpickle and skip the __iter__
and
extra json arguments because jsonpickle will ignore the missing
attributes. Thus any new val2 would have the static class initialization
supplied, but it would not run the initialization code in the __init__
ctor. This would become:
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'