Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/357.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 如何将树类对象结构序列化为json文件格式?_Python_Json_Serialization_Python 3.x - Fatal编程技术网

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

Python 如何将树类对象结构序列化为json文件格式?,python,json,serialization,python-3.x,Python,Json,Serialization,Python 3.x,给出下面的代码示例,如何使用Python3用JSON序列化这些类实例 class TreeNode(): def __init__(self, name): self.name = name self.children = [] 当我尝试执行json.dumps时,会出现以下错误: TypeError:JSON不可序列化 然后我发现,如果我将默认值设置为json.dumps以返回\uuuu dict\uuuu,我可以很好地序列化它,但是执行json.lo

给出下面的代码示例,如何使用Python3用JSON序列化这些类实例

class TreeNode():
    def __init__(self, name):
        self.name = name
        self.children = []
当我尝试执行
json.dumps
时,会出现以下错误:

TypeError:JSON不可序列化

然后我发现,如果我将默认值设置为
json.dumps
以返回
\uuuu dict\uuuu
,我可以很好地序列化它,但是执行
json.loads
会成为一个问题


我可以找到很多带有基本字符串的自定义编码器/解码器示例,但是没有一个示例有列表,在本例中是self.children。子节点列表将包含子节点及其子节点和其他节点。我需要一种方法来得到所有的东西

因为您处理的是树结构,所以使用嵌套字典是很自然的。下面的代码片段创建了
dict
的子类,并将自身用作实例的底层
\uuuuu dict\uuuuu
,这是我在许多不同上下文中遇到的一个有趣而有用的技巧:

(堆栈溢出)
(堆栈溢出)
(PyDoc.net)
(詹姆斯·罗伯特的博客)
(活性状态配方)
(活性状态配方)

事实上,我认为这是一个(不太著名的)Python成语。< /P>
class TreeNode(dict):
    def __init__(self, name, children=None):
        super().__init__()
        self.__dict__ = self
        self.name = name
        self.children = list(children) if children is not None else []
这解决了一半的序列化问题,但当使用
json.loads()
读回生成的数据时,它将是一个常规字典对象,而不是
TreeNode
的实例。这是因为
jsonecoder
可以对字典(及其子类)本身进行编码

解决这个问题的一种方法是向
TreeNode
类添加一个替代构造函数方法,可以调用该方法从
json.loads()
返回的嵌套字典重构数据结构

我的意思是:

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

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, 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, indent=2))
输出:

{
“名称”:“父项”,
“儿童”:[
{
“姓名”:“子女1”,
“儿童”:[]
},
{
“姓名”:“儿童2”,
“儿童”:[
{
“姓名”:“孙子”,
“儿童”:[
{
“名字”:“伟大的孙子”,
“儿童”:[]
}
]
}
]
}
]
}
pyobj类:树状结构
{
“名称”:“父项”,
“儿童”:[
{
“姓名”:“子女1”,
“儿童”:[]
},
{
“姓名”:“儿童2”,
“儿童”:[
{
“姓名”:“孙子”,
“儿童”:[
{
“名字”:“伟大的孙子”,
“儿童”:[]
}
]
}
]
}
]
}

这里有一个替代答案,基本上是我的Python 3版本,它对常规的
json
编码器尚未处理的任何Python对象进行了pickle处理

这里有几个不同之处。一个是它没有对
json
模块进行猴子补丁,因为这不是解决方案的基本部分。另一个原因是,尽管这次
TreeNode
类不是从
dict
类派生的,但它基本上具有相同的功能。这样做是为了防止stock
JSONEncoder
对其进行编码,并导致使用
JSONEncoder
子类中的
\u default()
方法

除此之外,它是一种非常通用的方法,能够处理许多其他类型的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\u str:{
“python对象”:“ganjx19tywlux18kvhjlzu5vzgukcqapgxebfxeckfgiaaay2hp”
“BGRYZW5XA11XBCHOACMBCQV9CQYOAA和CQDYBAAAG5HBWVxCFGH”
“AAAAQ2hpbGQgMXEJdWJoACmBcQp9cQsoaANdcQxoACmBcQ19cQ4o”
“AANDCQ9OACMBCRB9CREOANDCRJOCFGPAAAR3JLYXQGR3JHBMG”
“S2LKCrN1YMFCGJAAAR3JHBMQGS2LKCr1YMFCGHAAAAQ2HP”
“bgqgmnevdwjlahybgaafbhcmvudhewwiu”
}

整洁,非常感谢。现在,仅针对json.loads。当我们重新构建到Treenode中时,最好的方法是什么?Biff:你必须使用类似于我在回答你的评论时添加到我的答案中的替代构造函数方法(但没有在这里发布评论明确通知你,我现在所做的只是为了其他读者的利益)。