Python 深入理解yield


Posted in Python onSeptember 06, 2008

只是粗略的知道yield可以用来为一个函数返回值塞数据,比如下面的例子:

def addlist(alist):
    
for i in alist:
        
yield i + 1
取出alist的每一项,然后把i + 1塞进去。然后通过调用取出每一项:
alist = [1234]
for x in addlist(alist):
    
print x,
这的确是yield应用的一个例子,但是,看过limodou的文章《2.5版yield之学习心得》,并自己反复体验后,对yield有了一个全新的理解。

1. 包含yield的函数

假如你看到某个函数包含了yield,这意味着这个函数已经是一个Generator,它的执行会和其他普通的函数有很多不同。比如下面的简单的函数:
def h():
    
print 'To be brave'
    
yield 5

h()

可以看到,调用h()之后,print 语句并没有执行!这就是yield,那么,如何让print 语句执行呢?这就是后面要讨论的问题,通过后面的讨论和学习,就会明白yield的工作原理了。

2. yield是一个表达式

Python2.5以前,yield是一个语句,但现在2.5中,yield是一个表达式(Expression),比如:
= yield 5
表达式(yield 5)的返回值将赋值给m,所以,认为 m = 5 是错误的。那么如何获取(yield 5)的返回值呢?需要用到后面要介绍的send(msg)方法。

3. 透过next()语句看原理

现在,我们来揭晓yield的工作原理。我们知道,我们上面的h()被调用后并没有执行,因为它有yield表达式,因此,我们通过next()语句让它执行。next()语句将恢复Generator执行,并直到下一个yield表达式处。比如:
def h():
    
print 'Wen Chuan'
    
yield 5
    
print 'Fighting!'

= h()
c.next()
c.next()调用后,h()开始执行,直到遇到yield 5,因此输出结果:
Wen Chuan
当我们再次调用c.next()时,会继续执行,直到找到下一个yield表达式。由于后面没有yield了,因此会??出异常:
Wen Chuan
Fighting!
Traceback (most recent call last):
  File 
"/home/evergreen/Codes/yidld.py", line 11in <module>
    c.next()
StopIteration

4. send(msg) 与 next()

了解了next()如何让包含yield的函数执行后,我们再来看另外一个非常重要的函数send(msg)。其实next()和send()在一定意义上作用是相似的,区别是send()可以传递yield表达式的值进去,而next()不能传递特定的值,只能传递None进去。因此,我们可以看做
c.next() 和 c.send(None) 作用是一样的。
来看这个例子:
def h():
    
print 'Wen Chuan',
    m 
= yield 5  # Fighting!
    print m
    d 
= yield 12
    
print 'We are together!'

= h()
c.next()  
#相当于c.send(None)
c.send('Fighting!')  #(yield 5)表达式被赋予了'Fighting!'
输出的结果为:
Wen Chuan Fighting!
需要提醒的是,第一次调用时,请使用next()语句或是send(None),不能使用send发送一个非None的值,否则会出错的,因为没有yield语句来接收这个值。

5. send(msg) 与 next()的返回值

send(msg) 和 next()是有返回值的,它们的返回值很特殊,返回的是下一个yield表达式的参数。比如yield 5,则返回 5 。到这里,是不是明白了一些什么东西?本文第一个例子中,通过for i in alist 遍历 Generator,其实是每次都调用了alist.Next(),而每次alist.Next()的返回值正是yield的参数,即我们开始认为被压进去的东东。我们再延续上面的例子:
def h():
    
print 'Wen Chuan',
    m 
= yield 5  # Fighting!
    print m
    d 
= yield 12
    
print 'We are together!'

= h()
= c.next()  #m 获取了yield 5 的参数值 5
= c.send('Fighting!')  #d 获取了yield 12 的参数值12
print 'We will never forget the date', m, '.', d
输出结果:
Wen Chuan Fighting!
We will never forget the date 5 . 12

6. throw() 与 close()中断 Generator

中断Generator是一个非常灵活的技巧,可以通过throw抛出一个GeneratorExit异常来终止Generator。Close()方法作用是一样的,其实内部它是调用了throw(GeneratorExit)的。我们看:
def close(self):
    
try:
        self.throw(GeneratorExit)
    
except (GeneratorExit, StopIteration):
        
pass
    
else:
        
raise RuntimeError("generator ignored GeneratorExit")
# Other exceptions are not caught
因此,当我们调用了close()方法后,再调用next()或是send(msg)的话会抛出一个异常:
Traceback (most recent call last):
  File 
"/home/evergreen/Codes/yidld.py", line 14in <module>
    d 
= c.send('Fighting!')  #d 获取了yield 12 的参数值12
StopIteration

注:以上观点属于本人的个人理解,如有偏差请批评指正。谢谢!
Python 相关文章推荐
python中list常用操作实例详解
Jun 03 Python
Python  pip安装lxml出错的问题解决办法
Feb 10 Python
Python中正则表达式详解
May 17 Python
django框架自定义用户表操作示例
Aug 07 Python
django DRF图片路径问题的解决方法
Sep 10 Python
解决python 自动安装缺少模块的问题
Oct 22 Python
twilio python自动拨打电话,播放自定义mp3音频的方法
Aug 08 Python
python 控制Asterisk AMI接口外呼电话的例子
Aug 08 Python
将tensorflow.Variable中的某些元素取出组成一个新的矩阵示例
Jan 04 Python
python pandas利用fillna方法实现部分自动填充功能
Mar 16 Python
python zip,lambda,map函数代码实例
Apr 04 Python
Jupyter notebook如何修改平台字体
May 13 Python
Python 初始化多维数组代码
Sep 06 #Python
Python enumerate遍历数组示例应用
Sep 06 #Python
Python 拷贝对象(深拷贝deepcopy与浅拷贝copy)
Sep 06 #Python
Python httplib,smtplib使用方法
Sep 06 #Python
Python 命令行参数sys.argv
Sep 06 #Python
Python 时间处理datetime实例
Sep 06 #Python
Python linecache.getline()读取文件中特定一行的脚本
Sep 06 #Python
You might like
给ECShop添加最新评论
2015/01/07 PHP
ThinkPHP函数详解之M方法和R方法
2015/09/10 PHP
PHP添加PNG图片背景透明水印操作类定义与用法示例
2019/03/12 PHP
让广告代码不再影响你的网页加载速度
2006/07/07 Javascript
Prototype使用指南之selector.js
2007/01/10 Javascript
ExtJS GTGrid 简单用户管理
2009/07/01 Javascript
Js 回车换行处理的办法及replace方法应用
2013/01/24 Javascript
js跨域请求数据的3种常用的方法
2015/12/01 Javascript
详解AngularJS如何实现跨域请求
2016/08/22 Javascript
nodejs模块nodemailer基本使用-邮件发送示例(支持附件)
2017/03/28 NodeJs
JS 中document.write()的用法和清空的原因浅析
2017/12/04 Javascript
Bootstrap实现的表格合并单元格示例
2018/02/06 Javascript
JS文件中加载jquery.js的实例代码
2018/05/05 jQuery
浅谈在react中如何实现扫码枪输入
2018/07/04 Javascript
Vuex 使用及简单实例(计数器)
2018/08/29 Javascript
Three.JS实现三维场景
2018/12/30 Javascript
JavaScript如何获取一个元素的样式信息
2019/07/29 Javascript
通过js示例讲解时间复杂度与空间复杂度
2019/08/06 Javascript
小程序Request的另类用法详解
2019/08/09 Javascript
JS中多层次排序算法的实现代码
2021/01/06 Javascript
Python logging模块学习笔记
2014/05/24 Python
Python实现将不规范的英文名字首字母大写
2016/11/15 Python
python虚拟环境的安装和配置(virtualenv,virtualenvwrapper)
2019/08/09 Python
在python中计算ssim的方法(与Matlab结果一致)
2019/12/19 Python
Python基于jieba, wordcloud库生成中文词云
2020/05/13 Python
IE滤镜与CSS3效果(详细整理分享)
2013/01/25 HTML / CSS
深入理解css中vertical-align属性
2017/04/18 HTML / CSS
Araks官网:纽约内衣品牌
2020/10/15 全球购物
戴尔荷兰官方网站:Dell荷兰
2020/10/04 全球购物
出纳岗位职责
2013/11/09 职场文书
体育教育专业自荐信范文
2013/12/20 职场文书
优秀教师事迹简介
2014/02/02 职场文书
《黄山奇石》教学反思
2014/04/19 职场文书
领导干部“四风”问题批评与自我批评材料
2014/09/24 职场文书
金榜题名主持词
2015/07/02 职场文书
Redis批量生成数据的实现
2022/06/05 Redis