python-cookbook学习笔记九 迭代器与生成器二

时间:2021-08-13 16:03:42

我们来看下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_function1root是根节点。下面有child1child2 2个子节点。其中child1child2下面各自有3,4/5,6节点。我们做要实现一个节点的深度遍历。期望得到的结果是Node0,Node1,Node3,Node4,Node2,Node5,Node6.depth_first中用到了3yield语句。其中yield self是返回当前的根节点。yield c是返回根节点下的子节点. yield last是继续在上一步的基础上返回上一层的子节点。由于在__iter__中返回的是_child的迭代对象。因此上面的功能也就是不停地遍历各个节点下的_child对象。
执行结果如下:和我们预想的结果一致
python-cookbook学习笔记九 迭代器与生成器二

我们来看下单步调试的结果:

首先进入Node0节点
python-cookbook学习笔记九 迭代器与生成器二

打印出Node0

python-cookbook学习笔记九 迭代器与生成器二

开始遍历Node0的子节点,第一个是Node1

python-cookbook学习笔记九 迭代器与生成器二

此时ch=Node1

python-cookbook学习笔记九 迭代器与生成器二

打印出Node1
python-cookbook学习笔记九 迭代器与生成器二


接着遍历Node1的子节点。第一个是Node3
python-cookbook学习笔记九 迭代器与生成器二

Ch=Node3

python-cookbook学习笔记九 迭代器与生成器二

打印出Node3

python-cookbook学习笔记九 迭代器与生成器二

Node1的下一个子节点Node4

python-cookbook学习笔记九 迭代器与生成器二

python-cookbook学习笔记九 迭代器与生成器二

打印出Node4

python-cookbook学习笔记九 迭代器与生成器二

Node1遍历完后,开始遍历Node2
python-cookbook学习笔记九 迭代器与生成器二

首先打印出Node2
python-cookbook学习笔记九 迭代器与生成器二

python-cookbook学习笔记九 迭代器与生成器二

开始遍历node2,第一个子节点是node5
python-cookbook学习笔记九 迭代器与生成器二

python-cookbook学习笔记九 迭代器与生成器二

python-cookbook学习笔记九 迭代器与生成器二


最后一个是node6
python-cookbook学习笔记九 迭代器与生成器二

python-cookbook学习笔记九 迭代器与生成器二

python-cookbook学习笔记九 迭代器与生成器二



反向遍历列表。有一个列表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
 
结果如下:
python-cookbook学习笔记九 迭代器与生成器二



迭代器切片:
假设有如下的代码,count函数实现从n开始的加一操作
def count(n):

   
while True:

       
yield n

        n+=
1
for c in count(5):

   
print c
当开始遍历的时候。会一直打印从5开始的加一结果。但是我们只是想得到其中一部分的结果。比如第1015个生成结果
c=count(<span lang="EN-US" style="" color:"="">5)

print c[10:15]
报如下错误,无法进行数据切片
python-cookbook学习笔记九 迭代器与生成器二


如果要对生成器进行切片,要用到itertools.islice功能,代码改造如下:
c=count(5)

for x in itertools.islice(c,10,15):

   
print x
结果如下,得到了我们想要的结果
python-cookbook学习笔记九 迭代器与生成器二