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 ldap实现登录实例代码
Sep 30 Python
Django 2.0版本的新特性抢先看!
Jan 05 Python
python导出hive数据表的schema实例代码
Jan 22 Python
Python实现读取txt文件并转换为excel的方法示例
May 17 Python
详解Django+Uwsgi+Nginx 实现生产环境部署
Nov 06 Python
python3实现指定目录下文件sha256及文件大小统计
Feb 25 Python
Python操作远程服务器 paramiko模块详细介绍
Aug 07 Python
详解Python并发编程之从性能角度来初探并发编程
Aug 23 Python
Keras自定义实现带masking的meanpooling层方式
Jun 16 Python
matplotlib subplot绘制多个子图的方法示例
Jul 28 Python
Python的scikit-image模块实例讲解
Dec 30 Python
python+selenium自动化实战携带cookies模拟登陆微博
Jan 19 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将数据导入到Foxmail
2006/10/09 PHP
打造计数器DIY三步曲(中)
2006/10/09 PHP
php Xdebug 调试扩展的安装与使用.
2010/03/13 PHP
PHP解析RSS的方法
2015/03/05 PHP
微信公众号OAuth2.0网页授权问题浅析
2017/01/21 PHP
PHP中PDO事务处理操作示例
2018/05/02 PHP
利用js跨页面保存变量做菜单的方法
2008/01/17 Javascript
JavaScript 动态将数字金额转化为中文大写金额
2009/05/14 Javascript
浅析LigerUi开发中谨慎载入common.css文件
2013/07/09 Javascript
Jquery中children与find之间的区别详细解析
2013/11/29 Javascript
jQuery实现向下滑出的平滑下拉菜单效果
2015/08/21 Javascript
jquery实现图片切换代码
2016/10/13 Javascript
使用JavaScript根据图片获取条形码的方法
2017/07/04 Javascript
使用sessionStorage解决vuex在页面刷新后数据被清除的问题
2018/04/13 Javascript
mpvue 页面预加载新增preLoad生命周期的两种方式
2019/10/17 Javascript
Vue props中Object和Array设置默认值操作
2020/07/30 Javascript
解决Vue项目中tff报错的问题
2020/10/21 Javascript
Python模拟登录验证码(代码简单)
2016/02/06 Python
使用Python制作微信跳一跳辅助
2018/01/31 Python
python使用turtle绘制分形树
2018/06/22 Python
Python读取stdin方法实例
2019/05/24 Python
对django2.0 关联表的必填on_delete参数的含义解析
2019/08/09 Python
关于pytorch中全连接神经网络搭建两种模式详解
2020/01/14 Python
Python接口自动化测试的实现
2020/08/28 Python
提供世界各地便宜的机票:Sky-tours
2016/07/21 全球购物
银行营业厅大堂经理岗位职责
2014/01/06 职场文书
户外活动策划方案
2014/03/12 职场文书
校优秀毕业生主要事迹
2014/05/26 职场文书
校庆标语集锦
2014/06/25 职场文书
施工安全责任书范本
2014/07/24 职场文书
2014年军人思想汇报范文
2014/10/12 职场文书
初中生毕业评语
2014/12/29 职场文书
2015年健康教育工作总结
2015/04/10 职场文书
成功的商业计划书这样写才最靠谱
2019/07/12 职场文书
uwsgi+nginx代理Django无法访问静态资源的解决
2021/05/10 Servers