[Python]生成器(generator)

生成器是可以迭代的(其本身就自带了next()操作),首先生成器是自定义迭代器一种途径,例如需要迭代输出0-9的随机序列,且不可重复。如果运用random.choice()的话那么无法避免重复。此时就可以进行自定义迭代器。

from random import randint
def randGen(aList):
    while len(aList) > 0:
        yield aList.pop(randint(0,len(aList)-1))
for i in randGen(range(10)):
    print i

关键就是yield,当函数中有yield的时候,此函数就是一个生成器。事实上在itertools模块中的迭代器生成函数其源码都是生成器(generator),可以参考Python帮助文档。

1.生成器中的next()操作当超出范围的时候就会产生一个StopIteration异常,for函数是可以捕捉这类异常的。

2.生成器函数在每次暂停执行时,函数体内的所有变量都将被封存(freeze)在生成器中,并将在恢复执行时还原,并且类似于闭包,即使是同一个生成器函数返回的生成器,封存的变量也是互相独立的。定义一个生成器来展示这个特点,这个例子中我们定义了一个生成器用于获取斐波那契数列。

def fibonacci(): 
    a=b=1
    yield a 
    yield b 
    while True:        
        a, b = b, a+b 
        yield b 

for num in fibonacci(): 
    if num > 100: break
    print num, 

输出为1 1 2 3 5 8 13 21 34 55 89
因为生成器可以挂起,所以无限循环并没有关系

3.生成器是可以带参数的,因为生成器函数也是函数的一种。以下为itertools.count的源码(其他itertools模块中的迭代器都是有参数的)。

def count(start=0, step=1):
    # count(10) --> 10 11 12 13 14 ...
    # count(2.5, 0.5) -> 2.5 3.0 3.5 ...
    n = start
    while True:
        yield n
        n += step

4.send():

send是除next外另一个恢复生成器的方法。Python 2.5中,yield语句变成了yield表达式,这意味着yield现在可以有一个值,而这个值就是在生成器的send方法被调用从而恢复执行时,调用send方法的参数。

>>> def repeater(): 
...   n = 0
...   while True: 
...     n = (yield n) 
... 
>>> r = repeater() 
>>> r.next() 
0
>>> r.send(10) 
10 

*调用send传入非None值前,生成器必须处于挂起状态,否则将抛出异常。所以为启动的生成器是不能传递非None值的,不过,未启动的生成器仍可以使用None作为参数调用send。

*如果使用next恢复生成器,yield表达式的值将是None。
5.close():
这个方法用于关闭生成器。对关闭的生成器后再次调用next或send将抛出StopIteration异常。
6.throw(type, value=None, traceback=None):
这个方法用于在生成器内部(生成器的当前挂起处,或未启动时在定义处)抛出一个异常



 

你可能感兴趣的:(python)