迭代器与生成器(二)
关于生成器(在Python中)
生成器可以称为特殊的迭代器,因为它具有可迭代的属性,也具备next方法,而它的特殊之处在于其具有协同程序的概念,从语法上讲,生成器是一个带yield语句的函数,从而保证生成器能暂停执行,返回中间的结果(这也是yield语句的功能,即返回一个只给调用者并暂停执行),当生成器的next方法被再次调用时,它会准确的从离开的地方继续执行。例如,通过列表生成式,我们可以直接创建一个列表。但是,受到内存限制,列表容量肯定是有限的。而且,创建一个包含特别多元素的列表,不仅占用很大的存储空间,而且如果仅仅需要访问几个元素,那绝大多数元素占用的空间都浪费了。但是,如果列表元素可以按照某种算法推算出来,在循环的过程中不断推算出后续的元素,这样就不必创建完整的list,从而节省大量的空间。据上述,这种一边循环一边计算的机制,并且具有上所述的挂起返回中间值并且多次继续的协同程序,谓之生成器(Generator)
关于协同程序
可以运行的独立函数调用,可以暂停或者挂起,同时保存现场,并从程序离开的地方重新开始。依靠挂起,完成cpu或者IO的切换,达到协程的意义。
构建生成器对象:
实例一:(调用生成器函数,获得一个生成器对象)
def simple_gen():
yield 1
yield 2
gen_obj = simple_gen()
print type(gen_obj)
运行结果:
<type 'generator'>
实例二:(把一个列表生成式的[]改成(),就创建了一个generator)
li = [i * i for i in range(10)]
print type(li)
gen = (i * i for i in range(10))
print type(gen)
运行结果:
<type 'list'>
<type 'generator'>
如何使用生成器
实例三:(手动迭代,当生成器对象无值返回时,一个StopIteration将会抛出)
>>> gen = (i * i for i in range(3))
>>> gen.next()
0
>>> gen.next()
1
>>> gen.next()
4
>>> gen.next()
Traceback (most recent call last):
File "<input>", line 1, in <module>
StopIteration
实例四:(python的for循环有next()调用和对StopIteration的处理)
gen = (i * i for i in range(3))
for i in gen:
print i
运行结果:
0
1
4
实例五:(利用send方法将值送给生成器,调用close方法,让生成器抛出异常)
>>> def sum(start=0):
num = start
while True:
#保证send()回来的数据值得到接收
var = (yield num)
if var is not None:
num = var
else:
num += 1
>>> t = sum(2)
>>> t.next()
2
>>> t.next()
3
>>> t.next()
4
>>> t.send(7)
7
>>> t.send(9)
9
>>>
>>> t.close()
>>> t.next()
实例六:(throw方法允许客户传入要抛出的任何类型的异常)
>>> def sum(start=0):
num = start
while True:
var = (yield num)
if var is not None:
num = var
else:
num += 1
>>> s = sum(1)
>>> s.next()
1
>>> s.next()
2
>>> s.throw(ValueError('Memada!!!'))
Traceback (most recent call last):
File "<input>", line 1, in <module>
File "<input>", line 4, in sum
ValueError: Memada!!!