Python - 生成器函数

2023-09-17 22:17:26

Python提供了一个生成器来创建自己的iterator function。 生成器是一种特殊类型的函数,它不返回单个值,而是返回具有一系列值的迭代器对象。 在生成器函数中,使用 yield 语句而不是 return 语句。 下面是一个简单的生成器函数。

def mygenerator():
    print('First item')
    yield 10
    print('Second item')
    yield 20
    print('Last item')
    yield 30

在上面的示例中,mygenerator()函数是一个生成器函数。它使用 yield 而不是返回关键字。 因此,这将在每次调用 yield 关键字时返回该值。但是,您需要为此函数创建一个迭代器,如下所示。

gen = mygenerator() 
val = next(gen) #First item
print(val) #10
val = next(gen) #Second item
print(val) #20
val = next(gen) #Last item
print(val) #30
val = next(gen) #error            

生成器函数不能包含 return 关键字。如果包含它,则它将终止函数。 yieldreturn 之间的区别在于,yield返回一个值并暂停执行,同时保持内部状态,而 return 语句返回一个值并终止函数的执行。

以下生成器函数包括返回关键字。

def mygenerator():
    print('First item')
    yield 10
    return
    print('Second item')
    yield 20
    print('Last item')
    yield 30

现在,执行上述函数,如下所示。

gen = mygenerator() 
gen = mygenerator()
val = next(gen) #First item
print(val) #10
val = next(gen) #error

如您所见,上面的生成器在获取第一项后停止执行,因为在yield第一项后使用了 return 关键字。

将 for 循环与生成器功能结合使用(Using for Loop with Generator Function)

生成器函数也可以使用 for 循环。

def get_sequence_upto(x):
    for i in range(x):
        yield i

正如您在上面看到的,get_sequence_upto函数使用 yield 关键字。 生成器的调用就像普通函数一样。 但是,在遇到 yield 关键字时,其执行将暂停。这会将迭代器流的第一个值发送到调用环境。但是,局部变量及其状态在内部保存。

上述生成器函数get_sequence_upto()可以调用如下。

seq = get_sequence_upto(5) 
print(next(seq)) #0
print(next(seq)) #1
print(next(seq)) #2
print(next(seq)) #3
print(next(seq)) #4
print(next(seq)) #error

当向迭代器对象发出next()时,函数将恢复。当next()遇到StopIteration错误时,该函数最终终止。

在下面的示例中,函数 square_of_sequence() 充当生成器。它在每次调用next()时依次产生一个数字的平方。

def square_of_sequence(x):
    for i in range(x):
        yield i*i

以下脚本演示如何调用上述生成器函数。

gen=square_of_sequence(5)
while True:
    try:
        print ("Received on next(): ", next(gen))
    except StopIteration:
        break

上面的脚本使用 try..except 块来处理StopIteration错误。一旦捕获到StopIteration错误,它将中断 while 循环。

输出:

Received on next(): 0
Received on next(): 1
Received on next(): 4
Received on next(): 9
Received on next(): 16

我们可以使用 for 循环遍历生成器上的元素。在这种情况下,将隐式调用next()函数,并且还会自动处理StopIteration

squres = square_of_sequence(5)
for sqr in squres:
    print(sqr)

输出:

0
1
4
9
16

注意: 生成器相对于迭代器的优点之一是元素是动态生成的。由于下一项仅在使用第一项后生成,因此它比迭代器更节省内存。

生成器表达式(Generator Expression)

Python 还提供了生成器表达式,这是定义简单生成器函数的较短方法。 生成器表达式是一个匿名生成器函数。下面是 square_of_sequence() 函数的生成器表达式。

squre = (x*x for x in range(5))
print(next(squre)) #0
print(next(squre)) #1                                            
print(next(squre)) #4                                            
print(next(squre)) #9                                            
print(next(squre)) #16

在上面的示例中,(x*x for x in range(5)) 是一个生成器表达式。表达式的第一部分是yield值,第二部分是集合的 for 循环。

生成器表达式也可以在函数中传递。它应该不带括号,如下所示。

import math
val = sum(x*x for x in range(5)) 
print(val)

在上面的示例中,生成器表达式不带括号传递到内置函数 sum 中。

本文内容总结: