由于您正在处理树结构,因此使用嵌套字典是很自然的。下面代码的 sn-p 创建了一个 dict 的子类,并将其自身用作实例的底层 __dict__ — 这是我在许多不同上下文中遇到的一个有趣且有用的技巧:
Is it preferable to return an anonymous class or an object to use as a 'struct'? (stackoverflow)
How to use a dot “.” to access members of dictionary? (stackoverflow)
jsobject.py
(PyDoc.net)
Making Python Objects that act like Javascript Objects
(詹姆斯·罗伯特的博客)
AttrDict
(ActiveState 配方)
Dictionary with attribute-style access
(ActiveState 配方)
……事实上,我经常认为它是一个(鲜为人知的)Python 习语。
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 的实例。这是因为JSONEncoder 可以对字典(及其子类)本身进行编码。
解决此问题的一种方法是向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))
输出:
{
"name": "Parent",
"children": [
{
"name": "Child 1",
"children": []
},
{
"name": "Child 2",
"children": [
{
"name": "Grand Kid",
"children": [
{
"name": "Great Grand Kid",
"children": []
}
]
}
]
}
]
}
pyobj class: TreeNode
{
"name": "Parent",
"children": [
{
"name": "Child 1",
"children": []
},
{
"name": "Child 2",
"children": [
{
"name": "Grand Kid",
"children": [
{
"name": "Great Grand Kid",
"children": []
}
]
}
]
}
]
}