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 23 Python
Python正则表达式分组概念与用法详解
Jun 24 Python
Android基于TCP和URL协议的网络编程示例【附demo源码下载】
Jan 23 Python
django js实现部分页面刷新的示例代码
May 28 Python
python中metaclass原理与用法详解
Jun 25 Python
Django框架安装方法图文详解
Nov 04 Python
将python2.7添加进64位系统的注册表方式
Nov 20 Python
Python3爬虫中识别图形验证码的实例讲解
Jul 30 Python
基于Python的一个自动录入表格的小程序
Aug 05 Python
几款Python编译器比较与推荐(小结)
Oct 15 Python
python函数指定默认值的实例讲解
Mar 29 Python
Python 匹配文本并在其上一行追加文本
May 11 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
ThinkPHP实现批量删除数据的代码实例
2014/07/02 PHP
PHP高手需要要掌握的知识点
2014/08/21 PHP
关于jQuery中的end()使用方法
2011/07/10 Javascript
关于图片按比例自适应缩放的js代码
2011/10/30 Javascript
web的各种前端打印方法之jquery打印插件PrintArea实现网页打印
2013/01/09 Javascript
jquery选择器之内容过滤选择器详解
2014/01/27 Javascript
javascript格式化json显示实例分析
2015/04/21 Javascript
js实现跨域的方法实例详解
2015/06/24 Javascript
jQuery拖动元素并对元素进行重新排序
2015/12/30 Javascript
详解nodejs 文本操作模块-fs模块(一)
2016/12/22 NodeJs
Express之get,pos请求参数的获取
2017/05/02 Javascript
vue 中自定义指令改变data中的值
2017/06/02 Javascript
自定义类似于jQuery UI Selectable 的Vue指令v-selectable
2017/08/23 jQuery
使用Vue.js和Element-UI做一个简单登录页面的实例
2018/02/23 Javascript
让axios发送表单请求形式的键值对post数据的实例
2018/08/11 Javascript
详解在React-Native中持久化redux数据
2019/05/22 Javascript
Vue响应式原理Observer、Dep、Watcher理解
2019/06/06 Javascript
express如何解决ajax跨域访问session失效问题详解
2019/06/20 Javascript
Ajax请求时无法重定向的问题解决代码详解
2019/06/21 Javascript
扫微信小程序码实现网站登陆实现解析
2019/08/20 Javascript
jquery实现掷骰子小游戏
2019/10/24 jQuery
python文件读写并使用mysql批量插入示例分享(python操作mysql)
2014/02/17 Python
pycharm 使用心得(八)如何调用另一文件中的函数
2014/06/06 Python
django 2.0更新的10条注意事项总结
2018/01/05 Python
pytorch 图像中的数据预处理和批标准化实例
2020/01/15 Python
python3中使用__slots__限定实例属性操作分析
2020/02/14 Python
CK美国官网:Calvin Klein
2016/08/26 全球购物
迪梵英国官方网站:Darphin英国
2017/12/06 全球购物
Kathmandu美国网站:新西兰户外运动品牌
2019/03/23 全球购物
财务部经理岗位职责
2014/02/03 职场文书
保护环境建议书400字
2014/05/13 职场文书
综合素质自我评价怎么写
2014/09/14 职场文书
夫妻双方自愿离婚协议书怎么写
2014/12/01 职场文书
2014年中职班主任工作总结
2014/12/16 职场文书
2015年超市收银员工作总结
2015/04/25 职场文书
导游词之嵊泗列岛
2019/10/30 职场文书