生成器提供了一种优雅的方法,可以让编写返回元素序列的函数所需的代码变得简单、高效。基于yield语句,生成器可以暂停函数并返回一个中间结果。该函数会保存执行上下文,稍后在必要时可以恢复。
def fibonacci():
a, b = 0, 1
while True:
yield b
a, b = b, a+b
这个函数返回一个generator对象,是特殊的迭代器,它知道如何保存上下文,可以被无限次调用,每次都会生成序列的下一个元素。
def power(values):
for value in values:
print('powering %s' % value)
yield value
def adder(values):
for value in values:
print('adding to %s' % value)
if value % 2 == 0:
yield value +3
else:
yield value + 2
生成器的另一个重要特性,就是能够利用next函数与调用的代码进行交互。yield变成了一个表达式,而值可以通过名为send的新方法进行传递。
def psychologist():
print('Please tell me your problems')
while True:
answer = (yield)
if answer is not None:
if answer.endswith('?'):
print("Don't ask yourself too much questions")
elif 'good' in answer:
print("Ahh that's good, go on")
elif 'bad' in answer:
print("Don't be so nagative")
下面是调用psychologist()的示例对话
In [12]: free = psychologist()
In [13]: next(free)
Please tell me your problems
In [14]: free.send('I feel bad')
Don't be so nagative
In [15]: free.send('Fuck you?')
Don't ask yourself too much questions
In [16]: free.send('ok, fuck your mom is good')
Ahh that's good, go on
send的作用和next类似,但会将函数定义内部传入的值变成yield的返回值。incident,这个函数可以根据客户端代码来改变自身行为。为完成这一行为,还添加了另外两个函数:throw和close。它们将向生成器抛出错误。
- throw:允许客户端代码发送要抛出的任何类型的异常。
- close:作用相同,但会引发特定的异常——GeneratorExit。这种情况下,生成器函数必须再次引发GeneratorExit或StopIteration。