我们来看下yield在类中的应用。代码如下:
class Node: def __init__(self,value): self._value=value self._child=[] def __repr__(self): return "Node%s" % self._value def add_child(self,node): self._child.append(node) def __iter__(self): return iter(self._child) def depth_first(self): yield self for c in self: yield c for last in c: yield last
def iter_function(): root=Node(0) child1=Node(1) child2=Node(2) root.add_child(child1) root.add_child(child2) child1.add_child(Node(3)) child1.add_child(Node(4)) child2.add_child(Node(5)) child2.add_child(Node(6)) for ch in root.depth_first(): print ch
在iter_function1中root是根节点。下面有child1和child2 2个子节点。其中child1和child2下面各自有3,4/5,6节点。我们做要实现一个节点的深度遍历。期望得到的结果是Node0,Node1,Node3,Node4,Node2,Node5,Node6.在depth_first中用到了3个yield语句。其中yield self是返回当前的根节点。yield c是返回根节点下的子节点. yield last是继续在上一步的基础上返回上一层的子节点。由于在__iter__中返回的是_child的迭代对象。因此上面的功能也就是不停地遍历各个节点下的_child对象。
执行结果如下:和我们预想的结果一致
我们来看下单步调试的结果:
首先进入Node0节点
打印出Node0
开始遍历Node0的子节点,第一个是Node1
此时ch=Node1
打印出Node1
接着遍历Node1的子节点。第一个是Node3
Ch=Node3
打印出Node3
Node1的下一个子节点Node4
打印出Node4
Node1遍历完后,开始遍历Node2
首先打印出Node2
开始遍历node2,第一个子节点是node5
最后一个是node6
反向遍历列表。有一个列表a=[1,2,3,4].想从列表末尾开始遍历。可以用reversed 来实现这个效果
a=[1,2,3,4] for x in reversed(a): print x
发现迭代只有在对象实现了__reversed__方法且对象大小是确定的情况下才起作用。如果不符合上述条件,必须先将对象转换成列表。
我们可以自定义__reversed__来实现反向迭代。
class CountDown(): def __init__(self,start): self.start=start def __iter__(self): n=self.start while n > 0: yield n n-=1 def __reversed__(self): n=1 while n<=self.start: yield n n+=1
for x in CountDown(5): print x print 'reversed result:\n' for x in reversed(CountDown(5)): print x
结果如下:
迭代器切片:
假设有如下的代码,count函数实现从n开始的加一操作
def count(n): while True: yield n n+=1
for c in count(5): print c
当开始遍历的时候。会一直打印从5开始的加一结果。但是我们只是想得到其中一部分的结果。比如第10到15个生成结果
c=count(<span lang="EN-US" style="" color:"="">5) print c[10:15]
报如下错误,无法进行数据切片
如果要对生成器进行切片,要用到itertools.islice功能,代码改造如下:
c=count(5) for x in itertools.islice(c,10,15): print x
结果如下,得到了我们想要的结果