简体   繁体   中英

How to serialize objects with json

Both the Child and Parent classes inherit from Python dictionary:

import json 

class Child(dict):
    def __init__(self, **kwargs):
        super(Child, self).__init__(**kwargs)

class Parent(dict):
    def __init__(self, **kwargs):
        super(Parent, self).__init__(**kwargs)

parent = Parent(child = Child())

print type(parent['child'])

prints:

<class '__main__.Child'>

After performing the serialization and de-serialization using json.dumps and json.loads the Parent['child'] becomes a regular dictionary:

dumped = json.dumps(parent)
loaded = json.loads(dumped)
parent_2 = Parent(**loaded)
print type(parent_2['child'])

prints:

<type 'dict'>

Question: how to make sure that after the serialization, the parent_2['child'] is the instance of the Child and not a regular Python dictionary?

loads makes a dictionary and that's that. After some trial and error I found it out. (Note: It looks like you are using legacy Python so the syntax may need some tweaking from this solution.)

import json


class Child(dict):
    def __init__(self, **kwargs):
        super(Child, self).__init__(**kwargs)


class Parent(dict):
    def __init__(self, **kwargs):
        super(Parent, self).__init__(**kwargs)


parent = Parent(child=Child())

print(type(parent['child']))

if __name__ == '__main__':
    dumped = json.dumps(parent)
    loaded = json.loads(dumped)
    parent_2 = Parent(child=Child(**loaded)) # Changed how you call Parent
    print(type(parent_2['child']))

Without calling the args of Parent with a dict initialized as Child , we can have no expectation of detecting the Child type unless you add additional logic to detect the type.

You could use pickle . It can be dangerous to unpickle unknown pickled objects(as they can be malicious).

read documentation https://docs.python.org/3/library/pickle.html as it contains more information.

import pickle
class Foo:
    attr = 'A class attribute'


with open('pickle_class.pk','wb') as f:
         pickle.dump(Foo,f)   

# we open the file for reading
with open('pickle_class.pk','rb') as f:

    Bar = pickle.load(f)

# Test if they are the same.
assert Bar==Foo,'Not the Same'

You can also compress.

import bz2
import pickle

with bz2.BZ2File('pickled_class', 'wb') as f:
    pickle.dump(Foo, s)

In some cases, as using multithreading and lambda, dill , third-party module, can be handy as pickle throws

PicklingError: Can't pickle <function <lambda> at 0x111d0a7b8>: attribute lookup <lambda> on __main__ failed

The flow and danger(unpickling malicious software) are the same:

import dill

class Foo:
    attr = 'A class attribute'

with open('pickle_class.pk','wb') as f:
    dill.dump(Foo,f) 

Read dill documentation: https://pypi.org/project/dill/

NB: Never-ever load unknown pickled file

There is a package called jsonpickle . It seems to do the trick;

import json
import jsonpickle

class Child(dict):
    def __init__(self, **kwargs):
        super(Child, self).__init__(**kwargs)

class Parent(dict):
    def __init__(self, **kwargs):
        super(Parent, self).__init__(**kwargs)

if __name__ == '__main__':
    parent = Parent(child=Child())
    dumped = jsonpickle.encode(parent)
    loaded = jsonpickle.decode(dumped)
    parent_2 = Parent(**loaded)
    print(type(parent_2['child']))

<class '__main__.Child'>

Note; for this to work, the Json will have information about the original object graph so that it can be restored.

('{"py/object": "__main__.Parent", "child": {"py/object": "__main__.Child", '
 '"__dict__": {}}, "__dict__": {}}')

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM