说说Python中的iterator,yield表达式及generator,coroutine

每次去看别人写的代码都有个yield,感觉超级geek,今天花点儿时间整理下。

按照顺序来:

1. iterator

iterator叫做迭代器,用来遍历可以序列化的数据,比如一个list,set 等,当然如果对象想要能够使用迭代器来遍历,只要在该对象的类中添加__iter__()方法,该方法返回一个迭代器对象,迭代器对象中需要实现next()方法,例子如下:

>>> class sequenceClass(object):…def __init__(self, *args):…self._data = list(args)…def __iter__(self):…return DataIter(self)…>>> class DataIter(object):…def __init__(self, data):…self._index = 0…self._data = data._data…def next(self):…if self._index >= len(self._data): raise StopIteration()…d = self._data[self._index]…self._index += 1…return d… >>> data = sequenceClass(1,2,3,4)>>> for x in data: print x… 1234执行方法如下:

创建对象data : data = sequenceClass(1,2,3,4) 使用for循环遍历data:

1.第一次for循环遍历data时,调用了data的__iter__()方法,该方法返回一个迭代器对象:DataIter

2.接着for循环每次调用DataIter对象的next()方法,next()方法返回数据

3.等到数据遍历完成时,抛出异常StopIteration, 该异常被for循环扑获,遍历结束。

以上是iterator的实现方法,但有一种更加简单的方式,但初学时可能不太好理解,就是使用yield表达式来遍历对象。

2.yield表达式及genetator

Python中,凡是含有yield的函数,被调用时都返回一个generator对象。generator设计的目的是能够更加简单的实现迭代器协议,例如上面的例子,需要单独写一个类来遍历数据,而用generator,直接一个yield表达式就可以用做迭代器了。

看一个例子:

>>> def test_generator():…s = 0…for i in xrange(10):…s = yield i * s…print 'i:', i…print 's:', s…print 'i * s', i * s… >>> t = test_generator()>>> t<generator object test_generator at 0x10403a820>>>> >>> t.next()0>>> t.send(10)i: 0s: 10i * s 010>>> t.send(11)i: 1s: 11i * s 1122

一步步讲解:

1.定义了一个函数叫做test_generator

2.调用test_generator,得到t对象

3.运行t时,是一个generator对象

4.t.next()或者t.send(None)启动generator对象, generator对象运行到yield,,将yield右面的表达式的值返回,并保存generator对象当前的状,因此,后面的打印都没有被执行。

5.t.send(10)

1)将输入的值10赋值给s

2)执行yield后面的表达式,即将所有print执行完毕,解析如下:

由于在第4步generator保存了对象的当前的状态,因此: i = 0, s是刚输入的值为10, i *s 当然就为0了,接着进入下一次循环,此时i= 1,执行yield表达式,结果得10,保存当前generator状态,返回10,generator停止运行。

6.t.send(11)

1)和第5步类似了,将11输入给s

2)因为第5步,generator保存了当前的对象的值,因此: i = 1, s是刚输入的值为11, i *s 当然就为11了,接着进入下一次循环,此时i= 2,执行yield表达式,结果得22,保存当前generator状态,返回22,generator停止运行。

7.接下来在调用t.send(num),和第5,6步一样,直到generator内部的循环完成,当再次调用时,将抛出异常:StopIteration

总结一下:

1.yield表达式, 四种形式:

a. 不接受输入值或者输入值是None

yield 1

b. 接受输入值

s = yield 1

c. 接受输入,但不返回数据,这样默认返回None

s = yield

d.既不接受输入,也不返回值,默认返回None

yield

第一种:当函数调用到yield时,返回yield的右边经过计算的值 ,这里说计算的意思是,yield后面可以写成函数,表达式等,

第二种:当函数调用到yield时,必须传入一个值,该值存入s中,然后返回yield后面的表达式的值并保存当前状态

第三种:只是将数据接受进来,然后执行yield后的语句,再次执行到yield时,保存当前状态并返回,这样的用例一般是

只打印一些处理消息,而不需要结果的方式。

第四种:这样的只能遍历generator内部的数据了。

2.使用generator的好处:

1)可以很方便的实现迭代器,即yield不接受输入值

2)使用generator可以减少内存的使用,因为遍历出来的值都是每次进行计算的,不用一次性全部计算完成,然后一个个

遍历,最终释放掉;另外可以在yield后面做一些操作,可以很随意的控制返回值。

3.coroutine 协程

使用yield的函数,若用send来控制,就算coroutine了,若用for循环来控制,就算generator或者iterator,使用方法大多见于

decorator, 如tornado中的gen.coroutine。

享受每一刻的感觉,欣赏每一处的风景,这就是人生。

说说Python中的iterator,yield表达式及generator,coroutine

相关文章:

你感兴趣的文章:

标签云: