Python中关键词yield详解

Python中关键词yield详解

今天系统看了一下yield的相关知识,作此文章来记录一下。

首先要学习yield的概念就要知道生成器的概念,生成器是一种可以简单有效的创建迭代器的工具。它们像常规函数一样撰写,但是在需要返回数据时使用yield语句。每当对它调用next(),生成器从它上次停止的地方重新开始(它会记住所有的数据值和上次执行的语句)。

可迭代对象
下面我们来看两个打印结果完全相同的代码:

>>> mylist = [x*x for x in range(3)]
>>> for i in mylist :
...    print(i)
>>> mygenerator = (x*x for x in range(3))
>>> for i in mygenerator :
...    print(i)

这两组代码的打印结果完全相同但是另有不同。对于第一种,mylist就是一个列表,占用一个列表的存储空间,之后还可以再次循环遍历;对于第二种,它实时生成数据,不全存在内存中,不过之后就不能再使用for i in mylist了。

yield关键字
在这里插入图片描述

如果你对yield的用法完全不了解,可以先把他当成是一个return
只不过下次运行时,代码会在yield处继续运行。我们来看几个例子就明白了。

def foo():
    print("starting...")
    while True:
        res = yield 4
        print("res:",res)
g = foo()
print(next(g))
print("*"*20)
print(next(g))

你觉得它的打印结果会是什么呢?先想一想再往下看吧。

starting...
4
********************
res: None
4

ok,结果就像上图一样,我们慢慢来分析。
在第一个print(next(g))时,next相当于让迭代器往下走一步,初始值是4,结果自然是4.接着打印20个*号做标记。在之后又运行了一次next(g),那么这次就会在上次foo()函数中停止的地方运行,这时候res是没有值的,所以打印出res:None,再之后循环又到了yield时“return”了出来,print(next(g))的print打印出了4.

再来看一个例子:

>>> def echo(value=None):
...     print("Begin...")
...     try:
...         while True:
...             try:
...                 value = (yield value)
...             except Exception as e:
...                 value = e
...     finally:
...         print("Clean up!!!")
...
>>> generator = echo(1)
>>> print(next(generator))
Begin...
1
>>> print(next(generator))
None
>>> print(generator.send(2))
2
>>> generator.throw(TypeError, "spam")
TypeError('spam')
>>> generator.close()
Clean up!!!

在这里插入图片描述
这张图应该可以让你理解代码运行的步骤,这里不做过多解释了。当然也可以自己在IDE里实践观察一下。

最后再来看一个多个yield的例子吧:

def genter():
    a = 4
    b = 5
    c = 6
    for i in range(5):
        yield a
        print('a was print at ' + str(i))
        yield b
        print('b was print at ' + str(i))
        yield c
res = genter()
for i, c in enumerate(res):
    print('this is '+str(i)+' steps')
    if i > 1:
        break
    print('qq', c)

结果如下图:

this is 0 steps
qq 4
a was print at 0
this is 1 steps
qq 5
b was print at 0
this is 2 steps

运行的结果表明每次迭代停止在yield之后。你也可以修改代码进一步观察来理解。

最后我们再来说说为什么要用yield
在这里插入图片描述
当数据非常多时,显然生成器比列表这种东西合适得多。

后面再说一些关于yield的一些杂项小知识。
1.
send(msg)与next()的区别在于send可以传递参数给yield表达式,这时传递的参数会作为yield表达式的值,而yield的参数是返回给调用者的值。——换句话说,就是send可以强行修改上一个yield表达式值。比如函数中有一个yield赋值,a
= yield 5,第一次迭代到这里会返回5,a还没有赋值。第二次迭代时,使用.send(10),那么,就是强行修改yield 5表达式的值为10,本来是5的,那么a=10
2.带有 yield 的函数不再是一个普通函数,而是一个生成器generator,可用于迭代。
3.判断一个函数是否是一个特殊的generator函数可以利用isgeneratorfunction()判断。
4.要区分fab和fab(5),前者是generator function,后者是调用fab返回的一个generator,好比类的定义和类的实例的区别。
5.在for循环中相当于自动进行了next。

结尾
本文到这里就结束了,如果你有什么好的想法欢迎在评论里和我讨论,不对的地方我会修改。如果你觉得这篇文章对你有一点点的帮助的话记得点个赞再走哦~

感谢以下文章对我的帮助!:
https://www.runoob.com/w3cnote/python-yield-used-analysis.html
https://blog.csdn.net/mieleizhi0522/article/details/82142856
https://www.php.cn/python-tutorials-424969.html
https://www.zhihu.com/question/345210030/answer/841903171
https://www.jianshu.com/p/b635c48d63c5
有兴趣可以继续查看。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Wei *

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值