简单了解Python生成器是什么


Posted in Python onJuly 02, 2019

前言

生成器是 Python 初级开发者最难理解的概念之一,虽被认为是 Python 编程中的高级技能,但在各种项目中可以随处见到生成器的身影,你得不得去理解它、使用它、甚至爱上它。

提到生成器,总不可避免地要把迭代器拉出来对比着讲,生成器就是一个在行为上和迭代器非常类似的对象,如果把迭代器比作 Android 系统,那么生成器就是 iOS,二者功能上差不多,但是生成器更优雅。

什么是迭代器
顾名思义,迭代器就是用于迭代操作(for 循环)的对象,它像列表一样可以迭代获取其中的每一个元素,任何实现了 __next__ 方法 (python2 是 next)的对象都可以称为迭代器。

它与列表的区别在于,构建迭代器的时候,不像列表把所有元素一次性加载到内存,而是以一种延迟计算(lazy evaluation)方式返回元素,这正是它的优点。比如列表含有中一千万个整数,需要占超过400M的内存,而迭代器只需要几十个字节的空间。因为它并没有把所有元素装载到内存中,而是等到调用 next 方法时候才返回该元素(按需调用 call by need 的方式,本质上 for 循环就是不断地调用迭代器的next方法)。

以斐波那契数列为例来实现一个迭代器:

class Fib:
def __init__(self, n):
self.prev = 0
self.cur = 1
self.n = n
def __iter__(self):
return self
def __next__(self):
if self.n > 0:
value = self.cur
self.cur = self.cur + self.prev
self.prev = value
self.n -= 1
return value
else:
raise StopIteration()
# 兼容python2
def __next__(self):
return self.next()
f = Fib(10)
print([i for i in f])
#[1, 1, 2, 3, 5, 8, 13, 21, 34, 55]

什么是生成器

知道迭代器之后,就可以正式进入生成器的话题了。普通函数用 return 返回一个值,和 Java 等其他语言是一样的,然而在 Python 中还有一种函数,用关键字 yield 来返回值,这种函数叫生成器函数,函数被调用时会返回一个生成器对象,生成器本质上还是一个迭代器,也是用在迭代操作中,因此它有和迭代器一样的特性,唯一的区别在于实现方式上不一样,后者更加简洁

最简单的生成器函数:

>>> def func(n):
... yield n*2
...
>>> func
<function func at 0x00000000029F6EB8>
>>> g = func(5)
>>> g
<generator object func at 0x0000000002908630>
>>>

func 就是一个生成器函数,调用该函数时返回对象就是生成器 g ,这个生成器对象的行为和迭代器是非常相似的,可以用在 for 循环等场景中。注意 yield 对应的值在函数被调用时不会立刻返回,而是调用next方法时(本质上 for 循环也是调用 next 方法)才返回

>>> g = func(5)
>>> next(g)
10
>>> g = func(5)
>>> for i in g:
... print(i)
...
10

那为什么要用生成器呢?显然,用生成器在逼格上要比迭代器高几个等级,它没有那么多冗长代码了,而且性能上一样的高效,为什么不用呢?来看看用生成器实现斐波那契数列有多简单。

def fib(n):
prev, curr = 0, 1
while n > 0:
n -= 1
yield curr
prev, curr = curr, curr + prev
print([i for i in fib(10)])
#[1, 1, 2, 3, 5, 8, 13, 21, 34, 55]

生成器表达式

在前面一期「这样写代码更优雅」的文章里面曾经介绍过列表推导式(list comprehension),生成器表达式与列表推导式长的非常像,但是它俩返回的对象不一样,前者返回生成器对象,后者返回列表对象。

>>> g = (x*2 for x in range(10))
>>> type(g)
<type 'generator'>
>>> l = [x*2 for x in range(10)]
>>> type(l)
<type 'list'>

前面已经介绍过生成器的优势,就是迭代海量数据时,显然生成器更合适。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Python 相关文章推荐
python循环监控远程端口的方法
Mar 14 Python
python文件操作之目录遍历实例分析
May 20 Python
Centos Python2 升级到Python3的简单实现
Jun 21 Python
Python动刷新抢12306火车票的代码(附源码)
Jan 24 Python
python 使用poster模块进行http方式的文件传输到服务器的方法
Jan 15 Python
Python设置matplotlib.plot的坐标轴刻度间隔以及刻度范围
Jun 25 Python
Python Opencv提取图片中某种颜色组成的图形的方法
Sep 19 Python
Python3实现飞机大战游戏
Apr 24 Python
Python如何对XML 解析
Jun 28 Python
Python字节单位转换(将字节转换为K M G T)
Mar 02 Python
Python 机器学习工具包SKlearn的安装与使用
May 14 Python
使用pd.merge表连接出现多余行的问题解决
Jun 16 Python
Python OpenCV 调用摄像头并截图保存功能的实现代码
Jul 02 #Python
使用python实现ftp的文件读写方法
Jul 02 #Python
Python初学者常见错误详解
Jul 02 #Python
Python使用pyserial进行串口通信的实例
Jul 02 #Python
Python函数中参数是传递值还是引用详解
Jul 02 #Python
Python 运行.py文件和交互式运行代码的区别详解
Jul 02 #Python
python 函数中的内置函数及用法详解
Jul 02 #Python
You might like
php中cookie的作用域
2008/03/27 PHP
PHP中的生成XML文件的4种方法分享
2012/10/06 PHP
php include和require的区别深入解析
2013/06/17 PHP
使用基于jquery的gamequery插件做JS乒乓球游戏
2011/07/31 Javascript
用jquery实现输入框获取焦点消失文字
2013/04/27 Javascript
IE8下String的Trim()方法失效的解决方法
2013/11/08 Javascript
flash+jQuery实现可关闭及重复播放的压顶广告
2015/04/15 Javascript
js图片跟随鼠标移动代码
2015/11/26 Javascript
BootStrap实现邮件列表的分页和模态框添加邮件的功能
2016/10/13 Javascript
BootStrap 获得轮播中的索引和当前活动的焦点对象
2017/05/11 Javascript
JS请求servlet功能示例
2017/06/01 Javascript
Vue resource中的GET与POST请求的实例代码
2017/07/21 Javascript
JavaScript实现各种排序的代码详解
2017/08/28 Javascript
layui实现动态和静态分页
2018/04/28 Javascript
使用layer弹窗和layui表单实现新增功能
2018/08/09 Javascript
vue.js实现回到顶部动画效果
2019/07/31 Javascript
解决layui数据表格Date日期格式的回显Object的问题
2019/09/19 Javascript
微信小程序canvas分享海报功能
2019/10/31 Javascript
微信分享invalid signature签名错误踩过的坑
2020/04/11 Javascript
解决pyqt中ui编译成窗体.py中文乱码的问题
2016/12/23 Python
python 读取txt,json和hdf5文件的实例
2018/06/05 Python
python3-flask-3将信息写入日志的实操方法
2019/11/12 Python
python开发实例之Python的Twisted框架中Deferred对象的详细用法与实例
2020/03/19 Python
Nike挪威官网:Nike.com (NO)
2018/11/26 全球购物
哈利波特商店:Harry Potter Shop
2018/11/30 全球购物
美国在线宠物商店:Chewy
2019/01/12 全球购物
极简鞋类,赤脚的感觉:Lems Shoes
2019/08/06 全球购物
家得宝墨西哥官网:The Home Depot墨西哥
2019/11/18 全球购物
工商管理应届生求职信
2013/10/07 职场文书
建筑专业自荐信范文
2014/01/05 职场文书
2016年乡镇七一建党节活动总结
2016/04/05 职场文书
2019年最新借条范本!
2019/07/08 职场文书
教你快速开启Apache SkyWalking的自监控
2021/04/25 Servers
Java移除无效括号的方法实现
2021/08/07 Java/Android
Nginx反向代理、重定向
2022/04/13 Servers
PHP RabbitMQ消息列队
2022/05/11 PHP