如何将树类对象结构序列化为json文件格式?

Bif*_*iff 7 python serialization json python-3.x

鉴于下面的代码示例,如何使用Python 3使用JSON序列化这些类实例?

class TreeNode():
    def __init__(self, name):
        self.name = name
        self.children = []
Run Code Online (Sandbox Code Playgroud)

当我尝试做一个时,json.dumps我收到以下错误:

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

然后我才能发现,如果我将默认值设置json.dumps为返回,__dict__我可以将其序列化很好,但后来做了json.loads一个问题.

我可以找到许多带有基本字符串的自定义编码器/解码器示例,但是没有列表,在这种情况下是self.children.子列表将保存子节点及其子节点的其他节点.我需要一种方法来获得所有这些.

mar*_*eau 6

由于您要处理树结构,因此使用嵌套字典是很自然的。下面的代码片段创建了的子类,dict并将其用作__dict__实例的基础-这是我在许多不同环境中遇到的有趣且有用的技巧:

     返回匿名类或对象以用作“结构”是否更可取? (Stackoverflow)
     jsobject.py (PyDoc.net)
     制作类似于Javascript对象的Python对象 (James Robert的博客)
     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
Run Code Online (Sandbox Code Playgroud)

这解决了一半的序列化工作,但是当读取产生的数据时json.loads(),它将是一个常规的字典对象,而不是的实例TreeNode。这是因为JSONEncoder可以对字典(及其子类)本身进行编码。

解决该问题的一种方法是,向TreeNode该类添加替代构造函数方法,可以调用该方法从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))
Run Code Online (Sandbox Code Playgroud)

输出:

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