How to serialize the structure of objects of a tree class in json format?

Given the sample code below, how can I serialize these class instances using JSON using Python 3?

class TreeNode():
    def __init__(self, name):
        self.name = name
        self.children = []

When I try to do json.dumps, I get the following error:

TypeError: <TreeNode object at 0x7f6sf4276f60> is not JSON serializable

Then I managed to find that if I go back to json.dumpsthe default to return __dict__, I could serialize it in order, but then the problem json.loadsbecomes the problem.

I can find many custom examples of an encoder / decoder with basic strings, but none where there is a list, in this case self.children. The list of children will contain child nodes and their child nodes of other nodes. I need a way to get it all.

+6
2

, . dict __dict__ , , :

""? ( )
jsobject.py (PyDoc.net)
Python, Javascript ( )
AttrDict ( ActiveState)
( ActiveState)

... , , ( ) Python.

class TreeNode(dict):
    def __init__(self, name, children=None):
        super().__init__()
        self.__dict__ = self
        self.name = name
        self.children = [] if not children else children

, json.loads() , TreeNode. , JSONEncoder ( ).

TreeNode , json.loads() json.loads().

:

    @staticmethod
    def from_dict(dict_):
        """ Recursively (re)construct TreeNode-based tree from dictionary. """
        root = TreeNode(dict_['name'], dict_['children'])
        root.children = list(map(TreeNode.from_dict, root.children))
        return root

if __name__ == '__main__':
    import json

    tree = TreeNode('Parent')
    tree.children.append(TreeNode('Child 1'))
    child2 = TreeNode('Child 2')
    tree.children.append(child2)
    child2.children.append(TreeNode('Grand Kid'))
    child2.children[0].children.append(TreeNode('Great Grand Kid'))

    json_str = json.dumps(tree, sort_keys=True, indent=2)
    print(json_str)

    print()
    pyobj = TreeNode.from_dict(json.loads(json_str))  # reconstitute
    print('pyobj class: {}'.format(pyobj.__class__.__name__))  # -> TreeNode
    print(json.dumps(pyobj, sort_keys=True, indent=2))

:

{
  "children": [
    {
      "children": [],
      "name": "Child 1"
    },
    {
      "children": [
        {
          "children": [
            {
              "children": [],
              "name": "Great Grand Kid"
            }
          ],
          "name": "Grand Kid"
        }
      ],
      "name": "Child 2"
    }
  ],
  "name": "Parent"
}

pyobj class: TreeNode
{
  "children": [
      ... same as before ...
  ],
  "name": "Parent"
}
+5

, Python 3 " JSON, , Python, json ".

. , json , . TreeNode , TreeNode dict, . , JSONEncoder _default() JSONEncoder.

, Python, , .

import base64
from collections import MutableMapping
import json
import pickle

class PythonObjectEncoder(json.JSONEncoder):
    def default(self, obj):
        return {'_python_object': 
                base64.b64encode(pickle.dumps(obj)).decode('utf-8') }

def as_python_object(dct):
    if '_python_object' in dct:
        return pickle.loads(base64.b64decode(dct['_python_object']))
    return dct

# based on AttrDict -- https://code.activestate.com/recipes/576972-attrdict
class TreeNode(MutableMapping):
    """ dict-like object whose contents can be accessed as attributes. """
    def __init__(self, name, children=None):
        self.name = name
        self.children = list(children) if children is not None else []
    def __getitem__(self, key):
        return self.__getattribute__(key)
    def __setitem__(self, key, val):
        self.__setattr__(key, val)
    def __delitem__(self, key):
        self.__delattr__(key)
    def __iter__(self):
        return iter(self.__dict__)
    def __len__(self):
        return len(self.__dict__)

tree = TreeNode('Parent')
tree.children.append(TreeNode('Child 1'))
child2 = TreeNode('Child 2')
tree.children.append(child2)
child2.children.append(TreeNode('Grand Kid'))
child2.children[0].children.append(TreeNode('Great Grand Kid'))

json_str = json.dumps(tree, cls=PythonObjectEncoder, indent=4)
print('json_str:', json_str)
pyobj = json.loads(json_str, object_hook=as_python_object)
print(type(pyobj))

:

json_str: {
    "_python_object": "gANjX19tYWluX18KVHJlZU5vZGUKcQApgXEBfXECKFgIAAAAY2hp"
                      "bGRyZW5xA11xBChoACmBcQV9cQYoaANdcQdYBAAAAG5hbWVxCFgH"
                      "AAAAQ2hpbGQgMXEJdWJoACmBcQp9cQsoaANdcQxoACmBcQ19cQ4o"
                      "aANdcQ9oACmBcRB9cREoaANdcRJoCFgPAAAAR3JlYXQgR3JhbmQg"
                      "S2lkcRN1YmFoCFgJAAAAR3JhbmQgS2lkcRR1YmFoCFgHAAAAQ2hp"
                      "bGQgMnEVdWJlaAhYBgAAAFBhcmVudHEWdWIu"
}
<class '__main__.TreeNode'>
+1

Source: https://habr.com/ru/post/1540115/


All Articles