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中使用scapy模拟数据包实现arp攻击、dns放大攻击例子
Oct 23 Python
Python数据结构与算法之常见的分配排序法示例【桶排序与基数排序】
Dec 15 Python
Python常见工厂函数用法示例
Mar 21 Python
python中字符串变二维数组的实例讲解
Apr 03 Python
python把数组中的数字每行打印3个并保存在文档中的方法
Jul 17 Python
将Django项目部署到CentOs服务器中
Oct 18 Python
python DataFrame 取差集实例
Jan 30 Python
通过python实现随机交换礼物程序详解
Jul 10 Python
python数据库开发之MongoDB安装及Python3操作MongoDB数据库详细方法与实例
Mar 18 Python
python中opencv实现图片文本倾斜校正
Jun 11 Python
Python django中如何使用restful框架
Jun 23 Python
利用Python实现Picgo图床工具
Nov 23 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
长波知识介绍
2021/03/01 无线电
也谈截取首页新闻 - 范例
2006/10/09 PHP
动易数据转成dedecms的php程序
2007/04/07 PHP
php设计模式之命令模式使用示例
2014/03/02 PHP
php 在线导入mysql大数据程序
2015/06/11 PHP
php实现的简单数据库操作Model类
2016/11/16 PHP
Jquery带搜索框的下拉菜单
2013/05/06 Javascript
jQuery模拟新浪微博首页滚动效果的方法
2015/03/11 Javascript
ajax读取数据后使用jqchart显示图表的方法
2015/06/10 Javascript
Windows系统下安装Node.js的步骤图文详解
2016/11/15 Javascript
巧用canvas
2017/01/21 Javascript
jQuery实现用户输入自动完成功能
2017/02/13 Javascript
angular6.0开发教程之如何安装angular6.0框架
2018/06/29 Javascript
深入理解Vue.js轻量高效的前端组件化方案
2018/12/10 Javascript
webpack优化之代码分割与公共代码提取详解
2019/11/22 Javascript
jQuery操作动画完整实例分析
2020/01/10 jQuery
[03:36]DOTA2完美大师赛coL战队趣味视频——我演你猜
2017/11/23 DOTA
Python实现的生成自我描述脚本分享(很有意思的程序)
2014/07/18 Python
python中字典dict常用操作方法实例总结
2015/04/04 Python
举例讲解Python的Tornado框架实现数据可视化的教程
2015/05/02 Python
python 爬虫百度地图的信息界面的实现方法
2019/10/27 Python
基于python的列表list和集合set操作
2019/11/24 Python
Python 解决火狐浏览器不弹出下载框直接下载的问题
2020/03/09 Python
Python 将代码转换为可执行文件脱离python环境运行(步骤详解)
2021/01/25 Python
使用css3制作动感导航条示例
2014/01/26 HTML / CSS
Html5实现二维码扫描并解析
2016/01/20 HTML / CSS
Bobbi Brown芭比波朗美国官网:化妆师专业彩妆保养品品牌
2016/08/18 全球购物
Ben Sherman官方网站:英国男装品牌
2019/10/22 全球购物
英国网上自行车商店:Tredz Bikes
2019/10/29 全球购物
先进事迹报告会感言
2014/01/24 职场文书
汉语言文学毕业生自荐信范文
2014/03/24 职场文书
元宵晚会主持词
2014/03/25 职场文书
通信工程专业求职信
2014/06/04 职场文书
党委工作总结2015
2015/04/27 职场文书
Win11筛选键导致键盘失灵怎么解决? Win11关闭筛选键的技巧
2022/04/08 数码科技
MySQL解决Navicat设置默认字符串时的报错问题
2022/06/16 MySQL