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实现批量获取指定文件夹下的所有文件的厂商信息
Sep 28 Python
利用python模拟sql语句对员工表格进行增删改查
Jul 05 Python
Python面向对象之类和对象实例详解
Dec 10 Python
python三大神器之fabric使用教程
Jun 10 Python
Python GUI编程 文本弹窗的实例
Jun 11 Python
Python字符串对象实现原理详解
Jul 01 Python
一行python实现树形结构的方法
Aug 09 Python
Django 实现 Websocket 广播、点对点发送消息的代码
Jun 03 Python
Python连接HDFS实现文件上传下载及Pandas转换文本文件到CSV操作
Jun 06 Python
Python基于正则表达式实现计算器功能
Jul 13 Python
Django创建一个后台的基本步骤记录
Oct 02 Python
python爬虫智能翻页批量下载文件的实例详解
Feb 02 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
php中使用sftp教程
2015/03/30 PHP
php使用escapeshellarg时中文被过滤的解决方法
2016/07/10 PHP
php PDO实现的事务回滚示例
2017/03/23 PHP
PHP利用DWZ.CN服务生成短网址
2019/08/11 PHP
jQuery ui 1.7更新小结
2009/08/15 Javascript
深入理解JavaScript系列(26):设计模式之构造函数模式详解
2015/03/03 Javascript
Jquery1.9.1源码分析系列(六)延时对象应用之jQuery.ready
2015/11/24 Javascript
jQuery限制图片大小的方法
2016/05/25 Javascript
模拟javascript中的sort排序(简单实例)
2016/08/17 Javascript
JS表单验证方法实例小结【电话、身份证号、Email、中文、特殊字符、身份证号等】
2017/02/14 Javascript
JS简单封装的图片无缝滚动效果示例【测试可用】
2017/03/22 Javascript
jQuery中map函数的两种方式
2017/04/07 jQuery
Angular.JS中的this指向详解
2017/05/17 Javascript
详解React Native顶|底部导航使用小技巧
2017/09/14 Javascript
微信小程序模板和模块化用法实例分析
2017/11/28 Javascript
通过jquery toggleClass()属性制作文章段落更改背景颜色
2018/05/21 jQuery
详解使用React制作一个模态框
2019/03/14 Javascript
uploadify插件实现多个图片上传并预览
2019/09/30 Javascript
Vue组件模板及组件互相引用代码实例
2020/03/11 Javascript
解决vue单页面多个组件嵌套监听浏览器窗口变化问题
2020/07/30 Javascript
python smtplib模块实现发送邮件带附件sendmail
2018/05/22 Python
用Python从0开始实现一个中文拼音输入法的思路详解
2019/07/20 Python
浅谈Tensorflow 动态双向RNN的输出问题
2020/01/20 Python
Python开发之身份证验证库id_validator验证身份证号合法性及根据身份证号返回住址年龄等信息
2020/03/20 Python
Python的轻量级ORM框架peewee使用教程
2021/02/05 Python
Python tkinter实现日期选择器
2021/02/22 Python
JOSEPH官网:英国奢侈时尚品牌
2018/01/31 全球购物
Gina Bacconi官网:吉娜贝康尼连衣裙和礼服
2018/04/24 全球购物
出口公司经理求职简历中的自我评价
2013/10/13 职场文书
计算机应用职专应届生求职信
2013/11/12 职场文书
幼儿园教师教育感言
2014/02/28 职场文书
成龙霸王洗发水广告词
2014/03/14 职场文书
职业道德模范事迹材料
2014/08/24 职场文书
抗洪救灾感谢信
2015/01/22 职场文书
Python requests库参数提交的注意事项总结
2021/03/29 Python
win11自动弹出虚拟键盘怎么关闭? Win11关闭虚拟键盘的技巧
2023/01/09 数码科技