Python:yield关键字以及next、send函数的作用

yield与生成器

def func(n):
    for i in range(0, n):
        print('func: ', i)
        # yield i

f = func(10)
程序执行结果
func:  0
func:  1
func:  2
func:  3
func:  4
func:  5
func:  6
func:  7
func:  8
func:  9
当我们把注释去掉后:
def func(n):
    for i in range(0, n):
        print('func: ', i)
        yield i

f = func(10)
程序没有任何输出。
输出此函数:
print(func(10))
得到
<generator object func at 0x0000004B57353A98>

我们得出以下结论:
1、带有yield关键字的函数自动变成生成器
2、生成器被调用时不会立即执行
那么,怎么获得生成器的生成的值呢
使用next函数:
import time
def func(n):
    for i in range(0, n):
        print('func: ', i)
        yield i

f = func(10)
while True:
    print(next(f))
    time.sleep(1)
程序输出:
func:  0
0
func:  1
1
func:  2
2
func:  3
3
func:  4
4
func:  5
5
func:  6
6
func:  7
7
func:  8
8
func:  9
9
Traceback (most recent call last):
  File "C:/Users/mingC/PycharmProjects/pro_test/Demo/Demo4.py", line 9, in <module>
    print(next(f))
StopIteration

结论:
1、对于生成器,当调用函数next(generator)时,将获得生成器yield后面表达式的值;
2、当生成器已经执行完毕时,再次调用next函数,生成器会抛出StopIteration异常

扩展:
1、当生成器内部执行到return语句时,自动抛出StopIteration异常,return的值将作为异常的解释
2、外部可以通过generator.close()函数手动关闭生成器,此后调用next或者send方法将抛出异常

next与send函数

next函数与send函数很相似,都能获得生成器的下一个yield后面表达式的值,不同的是send函数可以向生成器传参
import time
def func(n):
    for i in range(0, n):
        arg = yield i
        print('func:', arg)

f = func(10)
while True:
    print('main:', next(f))
    print('main:', f.send(100))
    time.sleep(1)
输出结果:
main: 0
func: 100
main: 1
func: None
main: 2
func: 100
main: 3
func: None
main: 4
func: 100
main: 5
func: None
main: 6
func: 100
main: 7
func: None
main: 8
func: 100
main: 9
Traceback (most recent call last):
func: None
  File "C:/Users/mingC/PycharmProjects/pro_test/Demo/Demo4.py", line 9, in <module>
    print('main:', next(f))
StopIteration

程序首先调用next函数,使得生成器执行到第4行的时候,把i的值0作为next函数的返回值返回,程序输出main:0,然后生成器暂停。程序往下调用send(100)函数,
生成器从第四行继续执行,send函数的参数100作为yield的返回值,并赋值给arg,然后得到func:100的输出。
简单的说,send函数使得yield关键字拥有了返回值返回给它的左值。

常见错误

import time
def func(n):
    for i in range(0, n):
        arg = yield i
        print('func:', arg)

f = func(10)
while True:
    print('main:', f.send(100))
    time.sleep(1)
输出:
Traceback (most recent call last):
  File "C:/Users/mingC/PycharmProjects/pro_test/Demo/Demo4.py", line 9, in <module>
    print('main:', f.send(100))
TypeError: can't send non-None value to a just-started generator
错误说明显示:不能将一个非None的值传给初始的生成器

从上面的测试,我们知道,当调用send函数前,生成器内部应该执行到yield所在的语句并暂停。而在这次的测试中,我们从一开始就调用send并传了一个参数,
程序报错误。
因此,在调用带非空参数的send函数之前,我们应该使用next(generator)或者send(None)使得生成器执行到yield语句并暂停。
import time
def func(n):
    for i in range(0, n):
        arg = yield i
        print('func:', arg)

f = func(5)
print('main:', f.send(None))
while True:
    print('main:', f.send(100))
    time.sleep(1)
输出结果:
main: 0
func: 100
main: 1
func: 100
main: 2
func: 100
main: 3
func: 100
main: 4
func: 100
Traceback (most recent call last):
  File "C:/Users/mingC/PycharmProjects/pro_test/Demo/Demo4.py", line 10, in <module>
    print('main:', f.send(100))
StopIteration

关于yield from

yield from 用于生成器的嵌套。详细解释可以看这篇博文:http://blog.theerrorlog.com/yield-from-in-python-3.html

奋斗这是我写的第一篇博文,虽然知识点不多,但是也是对自己学习的一个小总结,希望以后能够坚持将自己编程路上的所思所想写到这里,感谢认真观看这篇博文的朋友们。
发布了88 篇原创文章 · 获赞 29 · 访问量 5万+
展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 技术黑板 设计师: CSDN官方博客

分享到微信朋友圈

×

扫一扫,手机浏览