深入理解python的yield和generator
原文发表在我的博客主页,转载请注明出处
前言
没有用过的东西,没有深刻理解的东西很难说自己会,而且被别人一问必然破绽百出。虽然之前有接触过python协程的概念,但是只是走马观花,这两天的一次交谈中,别人问到了协程,顿时语塞,死活想不起来曾经看过的东西,之后突然想到了yield,但为时已晚,只能说概念不清,所以本篇先缕缕python的生成器和yield关键字。
什么是生成器
- 生成器是一个特殊的程序,可以被用作控制循环的迭代行为
- 生成器类似于返回值为数组的一个函数,这个函数可以接收参数,可以被调用,但是,不同于一般的函数会一次性返回包含了所有数值的数组,生成器一次只产生一个值,这样消耗的内粗数量大大减少,而且允许调用函数可以很快的开始处理前几个返回值。因此,生成器看起来像一个函数但是表现的却像一个迭代器。
python中的生成器
python提供了两种基本的方式。
- 生成器函数:也是用def来定义,利用关键字yield一次返回一个结果,阻塞,重新开始
- 生成器表达式:返回一个对象,这个对象只有在需要的时候才产生结果
下面详细讲解。
生成器函数
为什么叫生成器函数?因为他随着时间的推移生成了一个数值队列。一般的函数在执行完毕之后会返回一个值然后退出,但是生成器函数会自动挂起,然后重新拾起继续执行,他会利用yield关键字关起函数,给调用者返回一个值,同时保留了当前的足够多的状态,可以使函数继续执行。生成器和迭代协议是密切相关的,可迭代的对象都有一个__next()__成员方法,这个方法要么返回迭代的下一项,要么引起异常结束迭代。
为了支持迭代协议,拥有yield语句的函数被编译为生成器,这类函数被调用时返回一个生成器对象,返回的对象支持迭代接口,即成员方法__next()__继续从中断处执行执行。
看下面的例子:
# codes
def create_counter(n):
print "create counter"
while True:
yield n
print 'increment n'
n += 1
cnt = create_counter(2)
print cnt
print next(cnt)
print next(cnt)
# output
<generator object create_counter at 0x0000000001D141B0>
create counter
2
increment n
3
分析一下这个例子:
- 在create_counter函数中出现了关键字yield,预示着这个函数每次只产生一个结果值,这个函数返回一个生成器(通过第一行输出可以看出来),用来产生连续的n值
- 在创造生成器实例的时候,只需要像普通函数一样调用就可以,但是这个调用却不会执行这个函数,这个可以通过输出看出来
- next()函数将生成器对象作为自己的参数,在第一次调用的时候,他执行了create_counter()函数到yield语句,返回产生的值2
- 我们重复的调用next()函数,每次他都会从上次被挂起的地方开始执行,直到再次遇到了yield关键字
为了更加深刻的理解,我们再举一个例子。
#coding
def cube(n):
for i in range(n):
yield i ** 3
for i in cube(5):
print i
#output
0
1
8
27
64
所以从理解函数的角度出发我们可以将yield类比为return,但是功能确实完全不同,在for循环中,会自动遵循迭代规则,每次调用next()函数,所以上面的结果不难理解。
生成器表达式:
生成器表达式来自于迭代和列表解析的组合,关于列表解析的概念和用法可以参见我之前的博客,生成器表达式和列表解析类似,但是他使用尖括号而不是方括号括起来的。如下代码:
>>> # 列表解析生成列表
>>> [ x ** 3 for x in range(5)]
[0, 1, 8, 27, 64]
>>>
>>> # 生成器表达式
>>> (x ** 3 for x in range(5))
<generator object <genexpr> at 0x000000000315F678>
>>> # 两者之间转换
>>> list(x ** 3 for x in range(5))
[0, 1, 8, 27, 64]
就操作而言,生成器表如果使用大量的next()函数会显得十分不方便,for循环会自动出发next函数,所以可以按下面方式使用:
>>> for n in (x ** 3 for x in range(5)):
print('%s, %s' % (n, n * n))
0, 0
1, 1
8, 64
27, 729
64, 4096
>>>
两者比较
一个迭代既可以被写成生成器函数,也可以被协程生成器表达式,均支持自动和手动迭代。而且这些生成器只支持一个active迭代,也就是说生成器的迭代器就是生成器本身。
总结
想起了初中时候老师经常说的,眼观千遍,不如手动一遍。
深入理解python的yield和generator的更多相关文章
- 【Python】深入浅出学习Python的yield和generator
背景 之前走马观花接触过Python协程的概念,这两天和一个同事聊到了协程,死活想不起来曾经看过的东西,就记得一个yield,概念不清: 所以想捋一捋相关的东西,此篇作为学习的记录. Generato ...
- python之yield和Generator
首先我们从一个小程序导入,各定一个list,找出其中的素数,我们会这样写 import math def is_Prims(number): if number == 2: return True / ...
- 【Python注意事项】如何理解python中间generator functions和yield表情
本篇记录自己的笔记Python的generator functions和yield理解表达式. 1. Generator Functions Python支持的generator functions语 ...
- Python高级语法之:一篇文章了解yield与Generator生成器
Python高级语法中,由一个yield关键词生成的generator生成器,是精髓中的精髓.它虽然比装饰器.魔法方法更难懂,但是它强大到我们难以想象的地步:小到简单的for loop循环,大到代替多 ...
- 深入理解Python中的yield和send
send方法和next方法唯一的区别是在执行send方法会首先把上一次挂起的yield语句的返回值通过参数设定,从而实现与生成器方法的交互. 但是需要注意,在一个生成器对象没有执行next方法之前,由 ...
- Python关键字yield的解释(stackoverflow)
3.1. 提问者的问题 Python关键字yield的作用是什么?用来干什么的? 比如,我正在试图理解下面的代码: def node._get_child_candidates(self, dista ...
- 深入理解Python中协程的应用机制: 使用纯Python来实现一个操作系统吧!!
本文参考:http://www.dabeaz.com/coroutines/ 作者:David Beazley 缘起: 本人最近在学习python的协程.偶然发现了David Beazley的co ...
- 深入理解 Python 异步编程(上)
http://python.jobbole.com/88291/ 前言 很多朋友对异步编程都处于"听说很强大"的认知状态.鲜有在生产项目中使用它.而使用它的同学,则大多数都停留在知 ...
- 提高你的python:解释 yield 和 Generators(生成器)
转自:http://www.oschina.net/translate/improve-your-python-yield-and-generators-explained 原文:http://www ...
随机推荐
- Learning The Bash Shell读书笔记(整理)
最近搞了一本书 Learning Bash Shell,发现有人已经写了阅读笔记,我就在这边整理一下 来自blog:http://blog.sina.com.cn/n4mine Learning Th ...
- js 获取json串中的值
用js中著名的eval函数var strJSON = "{name:'json name'}";//得到的JSONvar obj = eval( "(" + s ...
- 1、Hadoop的伪分布式部署
伪分布式模式搭建: 1.环境准备 (1)主机名(root用户) # vi /etc/sysconfig/network HOSTNAME=hadoo1 (不要用下划线) (2)创建普通用户cong ...
- 用php生成静态html页面(通用2种方法)
因为每次用户点击动态链接的时候都会对服务器发送数据查询的要求 对于一个访问量可能达百万千万级别的网站来说 这无疑是服务器一个大大的负担 所以把动态数据转换成静态html页面就成了节省人力物力的首选 因 ...
- GNU C 内联汇编介绍
GNU C 内联汇编介绍 简介 1.很早之前就听说 C 语言能够直接内嵌汇编指令.但是之前始终没有去详细了解过.最近由于某种需求,看到了相关的 C 语言代码.也就自然去简单的学习了一下如何在 C 代码 ...
- Android adb push 和 pull操作
由于安卓真机本地调试时,每次启动并生成apk然后安装到设备比较费时,而很多情况是仅仅修改了hot 脚本文件(cocos2dx + lua). 所以,使用热更机制把修改后的lua文件push到热更目录( ...
- PowerShell命令卸载Win10内置应用
Windows10系统预装了大批的应用,开始菜单右侧的磁贴即显示了其中的大部分,包括:人脉.日历.邮件.资讯.Xbox.Groove音乐.Camera相机.电影和电视.照片.手机助手.天气.OneNo ...
- Hadoop_MapReduce流程
Hadoop学习笔记总结 01. MapReduce 1. Combiner(规约) Combiner号称本地的Reduce. 问:为什么使用Combiner? 答:Combiner发生在Map端,对 ...
- UART Explained(转载)
做嵌入式开发,UART几乎是必不可少的,调试串口.GPS.GPRS.Bluetooth等模块很多都是用的UART接口.时下火热的IoT也不乏UART的身影,串口的BLE.WIFI.Zigbee.Lor ...
- POJ 3384 Feng Shui --直线切平面
题意:房间是一个凸多边形,要在里面铺设两条半径为r的圆形地毯,可以重叠,现在要求分别铺设到哪,使地毯所占的地面面积最大. 解法:要使圆形地毯所占面积最大,圆形地毯一定是与边相切的,这样才能使尽量不重叠 ...