linux yield_你常看到 Python 代码中的 yield 到底是什么鬼?

之前给大家说过,久久会解锁一篇 VIP 中的文章给大伙乐呵乐呵, 其实是被吐槽没有试看文。 d140649631b36040c9413ab1cf080827.gif好吧,今天就是这么出其不意攻其不备,就随便挑选一篇出来给你瞧瞧货色:  yield 到底是干屌的?

首先我们来看下这两个列表的区别:

49592c524796575b2d943af9d006f454.png
可以看到, list_1 是 [i for i in range(20)] ,而 list_2 是 (i for i in range(20)),主要区别就是一个是 [] , 一个是 (),而后者就是生成器。可以看到,当我们去执行 list_2 的时候,输出结果是一个 generator(生成器)对象。我们可以通过 next() 去调用这个生成器里面的元素:
de91131e627be3d7e2dbc7d294947a8c.png
我想到这里你会有点疑惑,就是它们之间有什么区别?我们这样,来计算一下以下这两个列表生成所需要的时间:
list_1 = [i for i in range(66666666)]list_2 = (i for i in range(66666666))
我们分别把它们放到方法里面执行,然后用装饰器的方式对它们各自的方法执行时间做个记录:
b0ce97cd1142b2ca534e75016aa3b8ee.png
执行结果如下:
c8079a1c49977124f345e9d92453d497.png
你会发现,方法二,也就是生成器生成的列表 list_2 所消耗的时间远低于 list_1。这是因为使用列表生成式生成的列表,是固定的,也就是说,当我们执行 [i for i in range(66666666)] 的时候, list_1 这个列表所封装的元素个数就是 66666666 个。而生成器生成的 list_2 就不是这样,它是记录了一定的算法规则,比如我们这里的 for i in range(66666666) 就是不断的 +=1 ,生成器只要记住这个规则就可以了,不需要将全部的数据都直接一股脑的装进 list_2 ,而是等到我们需要的时候,我们去调用的时候,它再去算一下,然后把相应的数据返回给我们。这,就是生成器,记住一点,它是根据一定的规律算法生成的,当我们去遍历它的时候,它可以通过特定的算法不断的推算出相应的元素,边运行边推算结果,从而节省了很多空间。体会下下面这两者的区别:
4e585d090bb361d00db1d96a36253080.png
知道了什么是生成器之后,咱们再来看看这个魔法关键词:yield。yield 和 return 有点相似,return 这个关键词你应该很熟悉吧,在函数中只要执行到这个关键词,就会返回相应的结果并且终止函数的执行:
0acdffc64ea8a225429f835ce91c6716.png
很好理解,这里返回 3 而不会继续返回 hahahahah。 那么 yield 又是怎么样的呢?咱们继续看:
060200b71b3f51c9e3e2650adc08264e.png
在这里面我们定义了一个 foo 方法,并且在里面定义了好几个 yield ,可是当我们调用这个方法的时候,居然跟什么都没有输出。那么我们来看看调用了这个 foo 函数之后得到的是什么类型:
285bb91ad77c4accaa98a6eba1604cbf.png
可以看到,它是一个生成器!是的,一个函数里面如果被定义了 yield ,那么这个函数就是一个生成器。我们可以通过 next 方法来使用这个生成器:
35dfb0dd15d22772776e1c580905e248.png
可以看到,当我们第一次调用的时候,遇到第一个 yield 的时候就跳出函数了,第二次调用的时候就是从第 1 个 yield 开始,第三个 yield 结束,以此类推。直到 next 没有数据之后报 StopIteration。既然它是一个生成器,那么我们就可以遍历它,我们具体打印出每个具体的元素,看看是什么:
b1ec97823bcbcee3c144943cfd90ac99.png
可以看到我们这里得到的都是 None ,这是因为我们 yield 的时候没有返回具体数据,我们可以这样:
eb2d0d29498d3a417bef2ecb620fed8b.png
这样我们就可以得到的生成器里面具体的元素了。不过呢,我们一般不会这么写,我刚刚说了,生成器是根据一定的规律算法生成的列表,当我们去遍历它的时候,它可以通过特定的算法不断的推断出相应的元素,边运行边推算结果,节省空间。所以 yield 一般会在 for 循环语句以一定的规则生成,举一个最简单的例子,生成这么些偶数:
1cd93ffe6542f1b63866b451d85b7840.png
这样我们在调用 foo 的时候就会得到一个生成器,然后就可以直接遍历使用。另外,yield 后面可以跟常用的数据类型,比如 string,int,dict:
eb8566b32a010ff87930327ea4431122.png

那么当你下次去调用相应的函数就会得到这样的 generator,于是就可以:OMG,根据对应的规则遍历它! 

ok,以上就是生成器和 yield 的用法,你以后还会经常看到它的身影,我们下回见, peace!

5e6c6afc654d19ca687303a7f597ad5f.gif

扫一扫

学习 Python 没烦恼

b740ae18006b1bbc356f39383a411f1b.png

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值