码迷,mamicode.com
首页 > 编程语言 > 详细

python yield

时间:2015-11-10 16:25:06      阅读:295      评论:0      收藏:0      [点我收藏+]

标签:

什么是yield?

    yield有点类似于continue和return的结合, 代码的运行的过程方式都是一样的, 执行完一行之后运行下一行.

    在continue里面(请查看注意事项里面的2说明), 当执行的代码遇到continue的时候, 就不会再执行后续的语句, 而是跳到循环的头部位置进行下一次循环.

    在yield里面(请查看注意事项里面的1说明), 当执行的代码遇到yield的时候, 就不会再执行后续的语句, 而是跳出函数, 并返回结果.


yield运行原理

场景1: 最简单的yield代码样例

[root@localhost ~]# vim test_yield.py
#!/bin/env python
# -.- coding:utf-8 -.-
def hello(n):
    print ‘yield之前‘
    n += 1
    yield n
    print ‘yield之后‘
    n *= 2
    print n
 
s = hello(100)
print ‘运行第一个next‘
s.next()

# 运行结果

[root@localhost ~]# python test_yield.py
运行第一个next
yield之前                      # 这个是输出结果.

总结: 通过这段代码可以看出来, 当执行的代码遇到yield的时候, 就不会再执行后续的语句, 而是跳出函数, 并返回结果.


场景2: 在场景1代码的例子上增加一个next(), 观察输出结果

[root@localhost ~]# vim test_yield.py
#!/bin/env python
# -.- coding:utf-8 -.-
def hello(n):
    print ‘yield之前‘
    n += 1
    yield n
    print ‘yield之后‘
    n *= 2
    print n
s = hello(100)
print ‘运行第一个next‘
s.next()
 
print ‘\n\n运行第二个next‘ # 增加了这行代码
s.next()                  # 增加了这行代码

# 运行结果

[root@localhost ~]# python test_yield.py
运行第一个next
yield之前
运行第二个next
yield之后
202
Traceback (most recent call last):
  File "test_yield.py", line 34, in <module>
    s.next()
StopIteration

总结: 通过这段代码可以看出来, 当第二次运行next的时候, 其实是先运行第一次阻断后面的内容, 然后才报错, 这个报错是因为没有next了.


场景3: 其实可以把yield理解为暂停功能.

#!/bin/env python
# -.- coding:utf-8 -.-
def get_time():
    from datetime import datetime
    return datetime.now()
 
def hello(n):
    for i in xrange(n):
        print ‘yield之前‘,
        print get_time()
        yield n
        print ‘yield之后‘,
        print get_time()
 
s = hello(5)
print ‘运行第一个next‘
s.next()
 
print ‘\n\n运行第二个next‘
s.next()
 
print ‘\n\n运行第三次next‘
s.next()
 
print ‘\n\n运行第四次next‘
s.next()
 
print ‘\n\n运行第五次next‘
s.next()
 
print ‘\n\n运行第六次next‘
s.next()

# 运行结果

[root@localhost ~]# python test_yield.py 
运行第一个next
yield之前 2015-11-10 01:58:31.753858
 
 
运行第二个next
yield之后 2015-11-10 01:58:31.753908
yield之前 2015-11-10 01:58:31.753941
 
 
运行第三次next
yield之后 2015-11-10 01:58:31.753952
yield之前 2015-11-10 01:58:31.753957
 
 
运行第四次next
yield之后 2015-11-10 01:58:31.753965
yield之前 2015-11-10 01:58:31.753970
 
 
运行第五次next
yield之后 2015-11-10 01:58:31.753977
yield之前 2015-11-10 01:58:31.753982
 
 
运行第六次next
yield之后 2015-11-10 01:58:31.753989
Traceback (most recent call last):
  File "test_yield.py", line 67, in <module>
    s.next()
StopIteration

总结: 通过上面这三个代码应该就已经大概知道yield是什么东西, 也知道它是怎么运作的了, 但是它老是报StopIteration这个错误.


场景4: 利用遍历来规避StopIteration错误

[root@localhost ~]# vim test_yield.py
#!/bin/env python
# -.- coding:utf-8 -.-
def get_time():
    from datetime import datetime
    return datetime.now()
 
def hello(n):
    for i in xrange(n):
        print ‘yield之前‘,
        print get_time()
        yield n
        print ‘yield之后‘,
        print get_time()
 
counter = 1
for i in hello(5):
    print ‘\n\n运行第%s个next‘ % counter
    counter += 1

# 运行结果

[root@localhost ~]# python test_yield.py
yield之前 2015-11-10 02:03:50.148205
 
 
运行第1个next
yield之后 2015-11-10 02:03:50.148256
yield之前 2015-11-10 02:03:50.148265
 
 
运行第2个next
yield之后 2015-11-10 02:03:50.148274
yield之前 2015-11-10 02:03:50.148279
 
 
运行第3个next
yield之后 2015-11-10 02:03:50.148286
yield之前 2015-11-10 02:03:50.148291
 
 
运行第4个next
yield之后 2015-11-10 02:03:50.148299
yield之前 2015-11-10 02:03:50.148304
 
 
运行第5个next
yield之后 2015-11-10 02:03:50.148311


场景5: yield传参

[root@localhost ~]# vim multi-para_yield.py
#!/bin/env python
# -.- coding:utf-8 -.-
 
def hello(n):
    for i in xrange(n):
        print ‘yield之前‘
        new_value = yield i
        print ‘yield之后‘
        print ‘new_value is:‘, new_value, i
 
s = hello(3)
print ‘\n\n第一次next‘
s.next()
print ‘\n\n第二次next‘
s.next()
print ‘\n\n第三次next(其实是send)‘
s.send(‘hello world!‘)

# 运行结果

[root@localhost ~]# python multi-para_yield.py 
 
 
第一次next
yield之前
 
 
第二次next
yield之后
new_value is: None 0
yield之前
 
 
第三次next(其实是send)
yield之后
new_value is: hello world! 1            # 重点在这里, 会发现传参和自身变量截然不同, 这应该是yield传参的固有写法.
yield之前


注意事项:

    1. yield只能写在函数里面, 不能写在函数外面.

    2. continue只能运行在循环语句中.

    3. 无法使用try来规避调用next时报的StopIteration错误.

    4. yield对象所有属性:

[‘__class__‘, ‘__delattr__‘, ‘__doc__‘, ‘__format__‘, ‘__getattribute__‘, ‘__hash__‘, ‘__init__‘, ‘__iter__‘, 

 ‘__name__‘, ‘__new__‘, ‘__reduce__‘, ‘__reduce_ex__‘, ‘__repr__‘, ‘__setattr__‘, ‘__sizeof__‘, ‘__str__‘, 

 ‘__subclasshook__‘, ‘close‘, ‘gi_code‘, ‘gi_frame‘, ‘gi_running‘, ‘next‘, ‘send‘, ‘throw‘]


python yield

标签:

原文地址:http://my.oschina.net/u/2452965/blog/528548

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!