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实现探测socket和web服务示例
Mar 28 Python
使用Python的内建模块collections的教程
Apr 28 Python
python实现的简单窗口倒计时界面实例
May 05 Python
深入浅析Python中join 和 split详解(推荐)
Jun 30 Python
matplotlib subplots 调整子图间矩的实例
May 25 Python
Win10下Python3.7.3安装教程图解
Jul 08 Python
在Django下测试与调试REST API的方法详解
Aug 29 Python
使用Python的networkx绘制精美网络图教程
Nov 21 Python
tensorflow的ckpt及pb模型持久化方式及转化详解
Feb 12 Python
Django之全局使用request.user.username的实例详解
May 14 Python
详细分析Python collections工具库
Jul 16 Python
基于python+selenium自动健康打卡的实现代码
Jan 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
PHP随机生成信用卡卡号的方法
2015/03/23 PHP
php+ajax实现无刷新动态加载数据技术
2015/04/28 PHP
PHP实现链式操作的核心思想
2015/06/23 PHP
PHP实现的大文件切割与合并功能示例
2018/04/10 PHP
php查询内存信息操作示例
2019/05/09 PHP
mysqli扩展无法在PHP7下升级问题的解决
2019/09/10 PHP
TP5框架安全机制实例分析
2020/04/05 PHP
js对象之JS入门之Array对象操作小结
2011/01/09 Javascript
jQuery调用WebService的实现代码
2011/06/19 Javascript
不用构造函数(Constructor)new关键字也能实现JavaScript的面向对象
2013/01/11 Javascript
js鼠标及对象坐标控制属性详细解析
2013/12/14 Javascript
可插入图片的TEXT文本框
2013/12/27 Javascript
如何用js实现鼠标向上滚动时浮动导航
2016/07/18 Javascript
JS获取input file绝对路径的方法(推荐)
2016/08/02 Javascript
利用Javascript实现BMI计算器
2016/08/16 Javascript
使用 jQuery.ajax 上传带文件的表单遇到的问题
2016/10/31 Javascript
JS实现选项卡效果的代码实例
2019/05/20 Javascript
在JavaScript中如何访问暂未存在的嵌套对象
2019/06/18 Javascript
Echarts.js无法引入问题解决方案
2020/10/30 Javascript
Python格式化压缩后的JS文件的方法
2015/03/05 Python
django与vue的完美结合_实现前后端的分离开发之后在整合的方法
2019/08/12 Python
PYTHON发送邮件YAGMAIL的简单实现解析
2019/10/28 Python
python读取tif图片时保留其16bit的编码格式实例
2020/01/13 Python
用python解压分析jar包实例
2020/01/16 Python
python利用文件时间批量重命名照片和视频
2021/02/09 Python
html5的localstorage详解
2017/05/09 HTML / CSS
ECCO英国官网:丹麦鞋履品牌
2019/09/03 全球购物
乌克兰珠宝大卖场:Zlato.ua
2020/09/27 全球购物
温泉秘密:Onsen Secret
2020/07/06 全球购物
元旦晚会邀请函
2014/02/01 职场文书
学校先进集体事迹材料
2014/05/31 职场文书
中国梦团日活动总结
2014/07/07 职场文书
工伤死亡理赔协议书
2014/10/20 职场文书
2015迎新晚会活动总结
2015/07/16 职场文书
初中美术教学反思
2016/02/17 职场文书
星际争霸:毕姥爷vs解冻01
2022/04/01 星际争霸