弄懂这 6 个问题,拿下 Python 生成器!
我的施工之路
2数字专题
4列表专题
7函数使用
10十大数据结构
11包和模块使用总结
13设计模式
15 Python 装饰器
16 Python 迭代器
施工计划第17篇。公众号真正做技术写作的本来就少,能够从一而终,始终坚持下去的,更是凤毛麟角,我会向我心中那些正真在做技术分享的前辈们学习,争取早日加入这类俱乐部。
正如施工专题计划开篇,我会牢记读者们的169个在看,砥砺前行:
叮嘱自己始终坚持每篇文章不吹不擂,不硬往谷歌、Facebook、华为师兄师姐,清华、北大、中科大,诸如此类上靠近乎。因为我知道,弄虚作假、搬弄是非、混淆视听,把时间拉长,最终结果都是搬起石头砸自己的脚,坑害的是整个圈子,圈子都没了还玩个鸟啊。
正如您所见,我写的这些专题文章,也都是老生常谈的话题,可能在网上一搜一大片,然而文章质量却参差不齐,叫人拍手叫好的文章始终不那么多。我会始终保持努力,争取为读者朋友们带来一些不一样的东西,这很难,但却很值得。
今天介绍生成器和yield的用法,通过如下8、9个小问题,相信大家会对它们有一点新的认识。
1 什么是可迭代对象?
可迭代对象,英文Iterable
,是一个形容词,这类对象和Java
语言类似,都可看作是一类接口,抽象地描述事物具备怎样的能力。所以,Iterable
自然具备可迭代能力。
如下,常见的list
,Iterator
等都是Iterable
对象:
In [33]: from collections.abc import Iterable,Iterator
In [34]: issubclass(list,Iterable)
Out[34]: True
In [35]: issubclass(Iterator,Iterable)
2 什么是一个生成器?
生成器是可迭代的(Iterable
),最简单的创建生成器方法是通过一对()
,如下所示:
In [37]: g = (i*i for i in [1,4,0])
In [38]: g
Out[38]: <generator object <genexpr> at 0x7fe8956e96d0>
g
是一个生成器对象,generator object
获取生成器对象的元素,可使用next
函数,如下所示,获取第一个元素:
In [39]: next(g)
Out[39]: 1
获取第二个元素:
In [40]: next(g)
Out[40]: 16
3 创建生成器的几种方法?
如上所见,使用一对()
能够创建一个生成器对象。
除此之外,想必大家也都知道,是使用关键字 yield
. yield
出现在一个函数中,运行到yield
处,返回的对象便是生成器对象(generator object).
4 生成器是迭代器吗?
生成器对象(generator object)一定也是迭代器对象(Iterator object),如上面的生成器g
,使用内置函数isinstance
验证,返回True
:
In [43]: isinstance(g,Iterator)
Out[43]: True
因此,它具备一切迭代器的特性,关于迭代器我们已在上一个话题讨论,简而言之,迭代器的几个特点:
- 是有去无回的,
- 迭代器无需提前知道整个列表的所有元素,
- 无需加载所有元素到RAM中尽而它是节省内存的(memory-efficient).
生成器同样具备这些特性。除此之外,它还有一些独有的特性,下面跟随yield
我们便能看出来。
5 如何用一句话描述 yield?
yield 关键字的用法在stackoverflow上也是最热的问题之一,借用一个最热回答中的解释:
“yield is a keyword that is used like return, except the function will return a generator. ”
yield
是一个特殊的return, 它返回一个生成器对象。
说实话,理解这些只是皮毛。那么,如何精通yield的用法呢?
6 如何精通yield的用法?
要想精通yield
,你必须首先搞清楚一点:
当你调用带有yield的函数时,函数并没有执行任何一行,只是返回一个生成器对象
为了帮助大家理解,创建一个带有yield的函数:
def gfun():
mylist = range(3)
for i in mylist:
yield i*i
g = gfun()
print(g)
为了加深印象,你可以自己调试验证一遍,函数第一行打的断点始终未被命中。
带yield
的函数和for
结合使用,第一次调用上一步创建的生成器对象后,将会进入函数体直到遇到yield
返回值。
然后,for循环再进入函数时,直接跑到yield
的下一句。直到生成器对象变空为止。
使用下面代码演示yield
的上面过程:
def createGenerator():
mylist = range(3)
for i in mylist:
yield i*i
print(i*i)
g = createGenerator()
print(g)
for gi in g:
pass
参考录制的gif:
7 yield 都有哪些重要价值?
Python引入yield后,便拥有具备实现协程的能力,协程的确是一种高效的编程模型,关于协程的理解,后面专题会详细讨论。包括更高级的功能如异步等,根基都是yield
.
8 yield 和 itertools
yield重要性和使用广泛性还提现在,Python单独一个模块专门用于管理迭代器和生成器对象,便是itertools
,里面封装的方法特性后面再讨论。
9 yield 使用案例
yield实现浮点数步长的frange
:
def frange(start,end,step):
i = start
while i<end:
yield round(i,3)
i+=step
调用frange
:
for item in frange(10,14,0.8):
print(item)
结果:
10
10.8
11.6
12.4
13.2
最后总结今天讨论的几个问题:
- 1 什么是可迭代对象?
- 2 什么是一个生成器?
- 3 创建生成器的几种方法?
- 4 生成器是迭代器吗?
- 5 如何用一句话描述 yield?
- 6 如何精通yield的用法?
- 7 yield 都有哪些重要价值?
- 8 yield 和 itertools
- 9 yield 使用案例
- 【Spring实战】—— 8 自动装配
- 【Spring实战】—— 7 复杂集合类型的注入
- 【Spring实战】—— 6 内部Bean
- 几款可替代Dreamweaver的HTML5开发工具
- Linux下的Telnet设置方法介绍
- 2017年11月互联网和相关服务业保持快速增长
- 深度学习胸部x射线
- C+实现神经网络之壹—Net类的设计和神经网络的初始化
- 死亡不可避免,但何时死,人工智能或有发言权
- 打开手机的这个功能,微信支付宝不怕盗刷!
- 手把手教你cuda5.5与VS2010的编译环境搭建
- Apache实现反向代理负载均衡
- linux下Apache服务器使用入门----httpd.conf
- linux下JBOSS使用入门
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法