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实现数通设备tftp备份配置文件示例
Apr 02 Python
通过Python来使用七牛云存储的方法详解
Aug 07 Python
Python文件读写保存操作的示例代码
Sep 14 Python
浅析python的优势和不足之处
Nov 20 Python
对json字符串与python字符串的不同之处详解
Dec 19 Python
PyQt5笔记之弹出窗口大全
Jun 20 Python
Python调用百度根据经纬度查询地址的示例代码
Jul 07 Python
Pytorch 抽取vgg各层并进行定制化处理的方法
Aug 20 Python
利用python实现PSO算法优化二元函数
Nov 13 Python
Python字节单位转换实例
Dec 05 Python
PyCharm 2019.3发布增加了新功能一览
Dec 08 Python
Python urllib request模块发送请求实现过程解析
Dec 10 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
网页游戏开发入门教程二(游戏模式+系统)
2009/11/02 PHP
PHP setTime 设置当前时间的代码
2012/08/27 PHP
php使用cookie保存用户登录的用户名实例
2015/01/26 PHP
PHP实现动态添加XML中数据的方法
2018/03/30 PHP
Vagrant(WSL)+PHPStorm+Xdebu 断点调试环境搭建
2019/12/13 PHP
JavaScript 类的定义和引用 JavaScript高级培训 自定义对象
2010/04/27 Javascript
jquery 表格排序、实时搜索表格内容(附图)
2014/05/19 Javascript
微信小程序 loading(加载中提示框)实例
2016/10/28 Javascript
微信小程序 页面跳转如何实现传值
2017/04/05 Javascript
简单介绍react redux的中间件的使用
2018/04/06 Javascript
vue非父子组件通信问题及解决方法
2018/06/11 Javascript
Vue不能检测到Object/Array更新的情况的解决
2018/06/26 Javascript
深入理解react-router 路由的实现原理
2018/09/26 Javascript
vue实现购物车抛物线小球动画效果的方法详解
2019/02/13 Javascript
Angular value与ngValue区别详解
2019/11/27 Javascript
[07:52]2014DOTA2 TI逗比武士游V社解说背后的故事
2014/07/10 DOTA
9种python web 程序的部署方式小结
2014/06/30 Python
python中pycurl库的用法实例
2014/09/30 Python
Python爬虫框架Scrapy实例代码
2018/03/04 Python
python 通过xml获取测试节点和属性的实例
2018/03/31 Python
python批量复制图片到另一个文件夹
2018/09/17 Python
pygame游戏之旅 调用按钮实现游戏开始功能
2018/11/21 Python
python3+opencv 使用灰度直方图来判断图片的亮暗操作
2020/06/02 Python
如何实现一个自定义类的序列化
2012/05/22 面试题
介绍下Lucene建立索引的过程
2016/03/02 面试题
类的返射机制中的包及核心类
2016/09/12 面试题
《最大的麦穗》教学反思
2014/04/17 职场文书
学校端午节活动方案
2014/08/23 职场文书
县委班子四风对照检查材料思想汇报
2014/09/29 职场文书
2014年店长工作总结
2014/11/17 职场文书
2014年企业党建工作总结
2014/12/18 职场文书
标枪加油稿
2015/07/22 职场文书
优质护理心得体会
2016/01/22 职场文书
民事纠纷协议书
2016/03/23 职场文书
2016年庆祝六一儿童节活动总结
2016/04/06 职场文书
Spring Boot优化后启动速度快到飞起技巧示例
2022/07/23 Java/Android