代码来自:pickle and cPickle – Python object serialization
首先树的结构,如图
import pickle
class Node(object):
"""A simple digraph where each node knows about the other nodes
it leads to.
"""
def __init__(self, name):
self.name = name
self.connections = []
return
def add_edge(self, node):
"Create an edge between this node and the other."
self.connections.append(node)
return
def __iter__(self):
return iter(self.connections)
def preorder_traversal(root, seen=None, parent=None):
"""Generator function to yield the edges via a preorder traversal."""
if seen is None:
seen = set()
yield (parent, root)
if root in seen:
return
seen.add(root)
for node in root:
for (parent, subnode) in preorder_traversal(node, seen, root):
yield (parent, subnode)
return
def show_edges(root):
"Print all of the edges in the graph."
for parent, child in preorder_traversal(root):
if not parent:
continue
print '%5s -> %2s (%s)' % (parent.name, child.name, id(child))
# Set up the nodes.
root = Node('root')
a = Node('a')
b = Node('b')
c = Node('c')
# Add edges between them.
root.add_edge(a)
root.add_edge(b)
a.add_edge(b)
b.add_edge(a)
b.add_edge(c)
a.add_edge(a)
print 'ORIGINAL GRAPH:'
show_edges(root)
# Pickle and unpickle the graph to create
# a new set of nodes.
dumped = pickle.dumps(root)
reloaded = pickle.loads(dumped)
print
print 'RELOADED GRAPH:'
show_edges(reloaded)
输出结果:
$ python pickle_cycle.py
ORIGINAL GRAPH:
root -> a (4299721744)
a -> b (4299721808)
b -> a (4299721744)
b -> c (4299721872)
a -> a (4299721744)
root -> b (4299721808)
RELOADED GRAPH:
root -> a (4299722000)
a -> b (4299722064)
b -> a (4299722000)
b -> c (4299722128)
a -> a (4299722000)
root -> b (4299722064)
其中preorder_traversal
是生成器。这里记录下生成器方法的每一步的意思。
# root 要遍历的根节点
# seen 保存遍历过的节点(集合)
# parent 每次yield的父节点,有可能不存在
def preorder_traversal(root, seen=None, parent=None):
"""Generator function to yield the edges via a preorder traversal."""
if seen is None: # 如果没有开始遍历,seen是空,初始化集合
seen = set()
yield (parent, root) # 记一次输出,这个要在下面判断之前
if root in seen: # 要遍历的根节点是否已经遍历过,防止循环遍历
return
seen.add(root) # 保存已遍历的“根”节点
for node in root: # 遍历子节点
for (parent, subnode) in preorder_traversal(node, seen, root):
yield (parent, subnode)
return
一开始不明白的地方是这样
yield (parent, root) # 记一次输出,这个要在下面判断之前
if root in seen: # 要遍历的根节点是否已经遍历过,防止循环遍历
return
为什么不是先判断呢。
看循环引用的情况。
前序输出从root -> a -> b -> a
这一路下来,有两个a
是正确的,
如果先判断要遍历的节点是否已经遍历过的话,那么b -> a
就走不通了,所以应该允许,点到就记一次输出,再来判断是否能继续往下走。b -> a
记一次输出,接下来发现a
已经遍历过它的子节点了(a in seen)
,才停止不往下遍历。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。