Python生成器next方法和send方法区别
生成器简介
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来接收似的。各位如果明白的欢迎指点。
原文和传送门如下:
恢复执行并将值“发送”到生成器函数中。所述 值参数成为当前产量表达的结果。该 send()方法返回由生成器产生的下一个值,或者StopIteration如果生成器退出而不产生另一个值则引发。当send()调用启动生成器时,必须将其None作为参数调用,因为没有可以接收该值的yield表达式。
更新:
2018-11-24
对生成器使用send(None)
方法,解释器在底层会调用__next__
方法,也就是next()
方法