简单了解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的Flask框架中使用日期和时间的教程
Apr 21 Python
Python常用的文件及文件路径、目录操作方法汇总介绍
May 21 Python
从源码解析Python的Flask框架中request对象的用法
Jun 02 Python
Python+tkinter使用80行代码实现一个计算器实例
Jan 16 Python
flask中的wtforms使用方法
Jul 21 Python
Django框架静态文件使用/中间件/禁用ip功能实例详解
Jul 22 Python
Python人工智能之路 之PyAudio 实现录音 自动化交互实现问答
Aug 13 Python
sklearn+python:线性回归案例
Feb 24 Python
python 连续不等式语法糖实例
Apr 15 Python
python:HDF和CSV存储优劣对比分析
Jun 08 Python
python如何使用腾讯云发送短信
Sep 17 Python
详解Django的MVT设计模式
Apr 29 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实例分享之二维数组排序
2014/05/15 PHP
php实现JWT验证的实例教程
2020/11/26 PHP
document.all还是document.getElementsByName?
2006/07/21 Javascript
得到文本框选中的文字,动态插入文字的js代码
2007/03/07 Javascript
multiSteps 基于Jquery的多步骤滑动切换插件
2011/07/22 Javascript
JS操作CSS随机改变网页背景实现思路
2014/03/10 Javascript
DOM操作一些常用的属性汇总
2015/03/13 Javascript
jquery实现简易的移动端验证表单
2015/11/08 Javascript
javascript定义类和类的实现实例详解
2015/12/01 Javascript
全面解析Javascript无限添加QQ好友原理
2016/06/15 Javascript
解决bootstrap导航栏navbar在IE8上存在缺陷的方法
2016/07/01 Javascript
详解VueJS应用中管理用户权限
2018/02/02 Javascript
Vue配合iView实现省市二级联动的示例代码
2018/07/27 Javascript
electron实现qq快捷登录的方法示例
2018/10/22 Javascript
jQuery pagination分页示例详解
2018/10/23 jQuery
js函数柯里化的方法和作用实例分析
2020/04/11 Javascript
[06:16]DOTA2守卫传承者——职业选手谈心路历程
2015/02/26 DOTA
Python 实现一个颜色色值转换的小工具
2016/12/06 Python
关于Python中空格字符串处理的技巧总结
2017/08/10 Python
python plotly绘制直方图实例详解
2019/07/22 Python
Python 字符串处理特殊空格\xc2\xa0\t\n Non-breaking space
2020/02/23 Python
详解HTML5 LocalStorage 本地存储
2016/12/23 HTML / CSS
英国工艺品购物网站:Minerva Crafts
2018/01/29 全球购物
经济学人订阅:The Economist
2018/07/19 全球购物
中医专业职业生涯规划书范文
2014/01/04 职场文书
优秀学生获奖感言
2014/02/15 职场文书
安全责任书范本
2014/04/15 职场文书
与美同行演讲稿
2014/09/13 职场文书
党的群众路线教育实践活动个人整改方案
2014/10/25 职场文书
2015年校长新年寄语
2014/12/08 职场文书
学术会议邀请函
2015/01/30 职场文书
北京英语导游词
2015/02/12 职场文书
音乐研修感悟
2015/11/18 职场文书
幼儿园开学家长寄语(2016秋季)
2015/12/03 职场文书
springboot读取nacos配置文件
2022/05/20 Java/Android
在SQL Server中使用 Try Catch 处理异常的示例详解
2022/07/15 SQL Server