Python中yield的作用:迭代生成器
整理自公众号:Devtogether
yield
为了搞清楚 yield 和 return 这两者的区别,我们先来看一个简单的例子:
>>> def self_return(n):
... print('rocky')
... while n > 0:
... print('before return')
... return n
... n -= 1
... print('after return')
...
>>> s = self_return(3)
rocky
before return
>>> s
3
从上面的例子中函数 self_return(n) 被调用的过程中我们可以清晰的看出,s = self_return(3) 函数体内的语句就开始执行了,遇到 return 以后将值返回,并结束在函数体内的执行,所以我们看到的结果是 return 后面的语句根本没有执行,这个是 return 的特点,不知道你还记得么?如果不记得的话可以去翻我前面的文章。
下面我们来将 return 换乘 yield ,再来试试看:
>>> def self_yield(n):
... print('rocky')
... while n > 0:
... print('before yield')
... yield n
... n -= 1
... print('after yield')
...
>>> s = self_yield(3)
>>> s.__next__()
rocky
before yield
3
仔细观察上面的例子你会发现,s = self_yield(n) 并没有去执行函数体内的语句,且 s.next() 的时候遇到 yield 的时候,会返回值,并且暂停。我们接着再继续来试一下:
>>> s.__next__()
after yield
before yield
2
>>> s.__next__()
after yield
before yield
1
>>> s.__next__()
after yield
Traceback (most recent call last):File "<stdin>", line 1, in <module>
StopIteration
通过上面的继续操作,我们可以看到每次遇到 yield 的时候都会返回值,并且暂停,下次再执行的时候是从上次暂停的位置开始又继续执行的,当没有满足条件的值,就会抛出异常。
结合上面的分析和对用例的执行结果,相信你已经你已经理解了 yield 的特点,也知道它与 return 之间的区别了:一般的函数,都是止于 return;作为生成器的函数,因为有了 yield,则遇到它会挂起。
下面我想再用一个例子来具体的阐述一下。斐波那契数列相信你们已经不陌生了,我在前面的文章中不止一次的提过它,这次我们尝试将 yield 应用到斐波那契数列中:
def fibs(max):"""fibonacci sequence generator"""n, a, b = 0, 0, 1while n < max:yield ba, b = b, a + bn += 1if __name__ == "__main__":f = fibs(9)for i in f:print(i,end = ' ')
上述代码的运行结果如下:
1 1 2 3 5 8 13 21 34 55
你看,用生成器生成的斐波那契数列是不是跟以前的不一样了呢?如果有兴趣的话,你可以将我在前面文章中演示过的斐波那契数列的实现方式和现在的做一下对比,然后仔细观察一下差异之处。
经过这几次的各种演示,其实已经很明确了:在一个函数中如果有了 yield 语句,那么它就是生成器,即也是迭代器。这种方式比前面写迭代器的类要简便的多,但这不是说迭代器不好,无论是使用迭代器还是生成器都要具体问题具体分析。
yield 的作用是在调用的时候返回相应的值,一次返回一个结果,在每个结果中间挂起函数的状态(即暂停执行),下一次执行是从上次暂停的位置开始,继续向下执行。
下面我们来做一道题,要求写出「将一个全是整数的列表进行操作后只保留奇数」。相信大多数人都能很快的写出下面这样的函数:
def get_odd(lst):res = []for i in lst:if i % 2:res.append(i)return resdef main():lst = range(10)for i in get_odd(lst):print(i)if __name__ == '__main__':main()
上面这个没什么难度,既然我们学了「生成器」,我在前面还这么舔它,是不是我们该用生成器来做一下这道题?看看用生成器来做同样的功能,到底有什么不同:
def get_odd(lst):for i in lst:if i % 2:yield idef main():lst = range(10)for i in get_odd(lst):print(i)if __name__ == '__main__':main()
对比一下这个功能的两种做法,使用「生成器」以后,代码变的行数更少了(省去了对 res 的操作,不用把结果存在 res 里),代码整体看起来更清晰了(一看就知道干嘛的,不用一上来去想 res 是个什么鬼,append 进去的是个什么玩意儿)。
2.生成器表达式
「生成器表达式」和列表推导式类似。区别在于使用列表推导,一次会产生所有的结果,而用「生成器表达式」则不会这样,它是按需产生。
列表推导式的写法如下:
>>> res = [x for x in range(5)]
>>> res
[0, 1, 2, 3, 4]
生成器表达式就是将上面的 [] 变成 () 即可:
>>> res = (x for x in range(5))
>>> res
<generator object <genexpr> at 0x109d9f570>
>>> next(res)
0
>>> next(res)
1
>>> next(res)
2
>>> next(res)
3
我们也顺便简单的看一下「生成器」的优势在「生成器表达式」中是怎么体现的。如果我们想对一系列整数求和,直接用生成器可以写成下面这样:
>>> sum((x for x in range(5)))
10
当然为了方便起见,也可以省略圆括号,即写成下面这样:
>>> sum(x for x in range(5))
10
但是如果你用常规的写法去写,就会写成下面这样:
>>> sum([x for x in range(5)])
10
上面的代码先构造了一个列表,然后再用 sum 函数求和,多了一步,天差地别,光在时间效率上,就已经输掉了裤子。
所以综合上面文章所讲,「生成器」光在明面上的优点就有好几个:代码行数更少;代码更易读;时效更高...
Python中yield的作用:迭代生成器相关推荐
- python中yield的用法(生成器的讲解)
2 理解说明yield与生成器 在Python中,使用yield的函数被称为生成器函数(generator function). 生成器有两种方法:next()和send(),都可以调用生成器 yie ...
- Python中yield的作用??
包含yield语句的函数会被特地编译为生成器函数;当函数被调用时,他们返回一个生成器对象,这个对象支持迭代器接口.函数也许会有个return语句,但它的作用是用来yield产生值的.举例如下: 1 & ...
- python中 yield的用法和生成器generator的说明
详情: https://www.cnblogs.com/python-life/articles/4549996.html 转载于:https://www.cnblogs.com/Samuel-Leu ...
- python的yield是什么意思,python生成器是怎么使用的 python中yield是什么意思
python中return和yield怎么用的?两个有什么区别?你从未驯服过她,她只是在爱你的时候收起獠牙. yield yield是用于生成器.什么是生成器,你可以通俗的认为,在一个函数中,使用了y ...
- [翻译]Python中yield的解释
问题: Python中yield关键字的作用是什么?它做了什么? 例如,我想理解以下代码 def node._get_child_candidates(self, distance, min_dist ...
- Python中yield
在介绍yield前有必要先说明下Python中的迭代器(iterator)和生成器(Generator). 一.迭代器(iterator) 在Python中,for循环可以用于Python中的任何类型 ...
- python 中 yield 的使用
python中yield在函数中的使用 正是因为函数含有这个yield,所以,该函数不再是普通的函数,而是生成器函数(generator function).下面通过小例子来说明一下这个内置函数的特性 ...
- Python中yield和yield from的用法
yield 后面接的是 future 对象 调用方 委托生成器 yield from 直接给出循环后的结果 yield from 委托者和子生成器直接通信 yield from 直接处理stopIte ...
- Python中yield简单用法
Python中yield简单用法 你或许知道带有yield的函数在Python中被称之为generator,那何为 generator? 我们暂时抛开generator,先从一个常见编程题目开始,循序 ...
最新文章
- axi dma direct 模式 总结
- 《大型网站服务器容量规划》一2.1 什么是容量
- OpenGL阴影贴图
- 我对C++内存分配方式的一点看法
- 前端综合性文档和教程总结(持续更新)
- 使用Pycharm管理Python依赖库(不使用anaconda)
- 【笔记】如何配置kvm桥接网络
- ❤️马上七夕,不懂浪漫?带你用Python“码”上七夕【建议收藏】❤️
- SOLIDWORKS启动时出现脚本错误问题
- org.apache.hadoop.hive.ql.exec.mr.MapRedTask. Could not find status of job:job_1649726530586_123811
- 自然语言处理-jieba
- LaTeX局部改变字体类型
- 【计算机毕业设计】017学生公寓电费信息管理系统
- 华为NE5000E集群路由器荣获InfoVision奖
- L1-022 奇偶分家 (10 分) 含解题思路 C语言 位运算
- 博弈——五分钟知悉如何用线性规划做棋牌博弈
- springboot 与rabbitmq集成+生产者投递确认+消费者手动确认+TTL+死信队列+延时队列
- oracle提示 ORA-12154: TNS: 无法解析指定的连接标识符 OCIEnvCreate 失败, 返回代码为-1,但错误消息文本不可用...
- 风、寒、暑、湿、燥、火
- 本地计算机 上的 OracleOraDb11g_home1TNSListener 服务启动后停止