生成器简介
python中,含有yield关键字的对象就是一个生成器,每次调用next
方法时会执行到yield
后面的语句,然后返回yield
后面代码块的执行结果。其实也可以调用send方法
下面给个例子方便理解。
next方法
def foo():
bar_a = yield 1 # bar_a是语句块(yield 1)的返回值,默认为None
bar_b = yield bar_a
yield "最后一个值,再迭代就要报StopIteration了"
f = foo() # 创建生成器,此时没有执行foo()里的任何语句
print(next(f)) # 从foo()里进入,一直执行到(yield 1)处,此时变量bar_a还没有创建
print(next(f)) # 先将语句块(yield 1)的返回值赋值个bar_a,此时bar_a的值是None。
# 然后执行到语句块(yield bar_a),bar_b也还没有被创建
print(next(f)
输出:
>>>1
>>>None
>>>最后一个值,再迭代就要报StopIteration了
可以看出,f = foo()
创建生成器时,每次执行到yield
时,会跳出去并将yield
关键字后面的内容返回给调用者。下一次有别的调用者再次调用生成器时,会先恢复生成器上次的机器状态,再接着执行指导遇到yield
或者元素迭代完毕。
而且我们可以看到bar_a
和bar_b
是语句yield 1
和yield bar_a
的返回值,注意:不是生成器的返回值。
这里有个比较绕的地方,我们用bar_a = yield 1
做分析:
- 1是生成器的返回值。因为生成器返回
yield
后面的代码块 -
bar_a是语句
yield 1
的返回值,这就好比我们写a = print('my lover') print('a的值是:', a)
会输出:
>>>my lover >>>a的值是: None
send方法
def foo():
bar_a = yield 1
bar_b = yield bar_a
yield "最后一个值,再迭代就要报StopIteration了"
f = foo()
print(f.send(None))
print(f.send("my lover"))
print(next(f))
输出:
>>>1
>>>my lover
>>>最后一个值,再迭代就要报StopIteration了
这里f.send(None)
是初始化生成器,和next(f)
的效果一模一样。但是不推荐这么写,因为不规范。
注意输出的第二行是字符串my lover,而不是None。这是因为send
函数带有一个参数,这个参数会覆盖yield 1
语句的返回值,也就是bar_a的值现在不是None了。
FAQ
官网提到,当我们创建一个生成器时,第一次调用只能用next()
或者send(None)
。因为此时send传入其他参数也没有yield语句去接收。
这句话我看不懂,说的好像传入None就有yield来接收似的。各位如果明白的欢迎指点。
原文和传送门如下:
Resumes the execution and “sends” a value into the generator function. The value argument becomes the result of the current yield expression. The send() method returns the next value yielded by the generator, or raises StopIteration if the generator exits without yielding another value. When send() is called to start the generator, it must be called with None as the argument, because there is no yield expression that could receive the value.
Google翻译版本:
恢复执行并将值“发送”到生成器函数中。所述 值参数成为当前产量表达的结果。该 send()方法返回由生成器产生的下一个值,或者StopIteration如果生成器退出而不产生另一个值则引发。当send()调用启动生成器时,必须将其None作为参数调用,因为没有可以接收该值的yield表达式。
更新:
2018-11-24
对生成器使用send(None)
方法,解释器在底层会调用__next__
方法,也就是next()
方法
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。