Python 如何将树类对象结构序列化为json文件格式?
给出下面的代码示例,如何使用Python3用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
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
类派生的,但它基本上具有相同的功能。这样做是为了防止stockJSONEncoder
对其进行编码,并导致使用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:你必须使用类似于我在回答你的评论时添加到我的答案中的替代构造函数方法(但没有在这里发布评论明确通知你,我现在所做的只是为了其他读者的利益)。