python yield表达式总结(generator)

原创
2013/09/11 09:56
阅读数 1.5K

2014-3-4迭代器必须在类中实现,因为要实现 next, __iter__ 方法

一般在next里满足的停止迭代条件后要使用 raise StopIteration 来结束迭代,当然了,自定义异常抛出也行.

http://hi.baidu.com/rails7/item/5b033a437a8f75d2c0a59241

迭代器(对象)版本

#!/usr/bin/env python 
# -*- coding: utf-8 -*-

class Fib(object): 
    a = 0
    b = 1
        
    def next(self): 
        self.a, self.b = self.b, self.a + self.b
        # 超过10000后停止迭代 
        if self.a > 10000:
            raise StopIteration
        return self.a 
        
    def __iter__(self): 
        return self
        
        
fibs = Fib() 

for f in fibs: 
    print f

生成器(函数)版本

#!/usr/bin/env python 
# -*- coding: utf-8 -*-

def fib(): 
    a, b = 0, 1
    while True: 
        a, b = b, a+b 
        if a > 1000 and a < 5000:
            yield "1000 to 5000 don`t display"
            continue
        if a > 10000:
            raise StopIteration
        yield a 
        
for f in fib(): 
    print f

---------------------------

关于yield表达式(generator) 疑惑了很久, 昨晚坐公交翻看了 Manuals总结如下:

例子党, 直接上代码..

# -*- coding: utf-8 -*-

"""例子1
一个函数含有yield表达式 这个函数就不是普通函数,而是生成器(generator)
"""
def gen():
    print "start"                 #*0
    m = yield 2                   #*1 # yield意思是产生, 此表示产生2 就是调用可以返回2 (当然,返回是有条件的)
    print m                       #*2 
    n = yield 3                   #*3
    print n                       #*4

    try:                          #*5
        print "end"               #*6
    except StopIteration as e:    #*7
        print e                   #*8
        # raise e


# 先说明yield表达式, yield有点像<前置操作符>, 跟在表达式前面,用于把表达式的值返回给调用者, (yield 2)本身的值赋给m

g = gen()
""" result:
<generator object f at 0x01228EE0>
"""
#↑>>> 可以看出是一个generator, 此时并没有执行 *0和*1行
g.send(3)
""" result:
TypeError: can't send non-None value to a just-started generator
"""
#↑>>> 开始生成器不能send非空值
g.send(None) # 住: g.next()相当于g.send(None) 本人习惯用send而不是next
""" result:
start
2 #此时函数(生成器)返回了2(就是yield后的,此时你可以理解为yield相当于return,但是返回后暂停了执行)
"""
# 此时函数挂起(让出cpu使用权)并保持状态,直到遇到下一个next/send 
# g.send(None) 调用者把None这个消息send给上一个yield表达式,由于第一次调用,没有上一个yield.
# 到目前为止, 调用了一次send(None) 总结一下, 上面说到保持状态:目前函数运行到*1行并挂起
print g.send(5)
""" result:
5
3 #和上面一样,第二个yield生成(返回)的值为3
"""
# 此时函数从*1行后继续执行 通过调用g.send(5),调用者把5这个消息send给上一个yield表达式(yield 2) 既:(yield 2)这个整体的值,此时m = 5
# 到目前为止, 调用了一次send(None),一次send(5) 总结一下, 上面说到保持状态:1.此时的状态是:m(既yield 2这个整体的结果值)被调用者发送消息赋值为5 2.目前函数运行到*3行并挂起
print g.send(6)
#result:
# 6
# end
# StopIteration
# 此时函数从*3行后继续执行 通过调用g.send(6),调用者把6这个消息send给了上一个yield表达式(yield 3) 既:(yield 3)这个整体的值,此时n = 6
# 继续往下执行,由于没有了遇不到yield,所有会出现 StopIteration 异常而结束

# 到目前为止,生成器函数运行结束,由于生成器会记住状态, 再调用send/next还会出现StopIteration异常

# 通过生成器, 调用者和函数内部可以交互消息, 暂停执行, 可用同步代码处理异步, 如:tornado的 @gen修饰器, twisted的@inlineCallback修饰器...

"""例子2
在for循环迭代过程中, 系统自动回调用next方法,不用显示调用
"""
def foo(list2gen):
    for item in list2gen:
        yield item # 此时 yield有点像调用一次而不结束而是暂停执行的return ,这里的好处类似iterator, 要给你生成给你一个,而不是像list, 一下都给你,占用内存大

l = [2,3,4]

for i in foo(l): # 这里foo把l变成了生成器
    print i

# result:
# 2
# 3
# 4

"""例子3
一个模拟无穷列表的情况(此处必须用生成器)
"""
def g():
    n = 0
    while True:
        yield n
        n += 1

# 哈哈,无限生成 递增数, 一直打印, 直到(内存耗尽?)
for i in g():
    print i

展开阅读全文
加载中

作者的其它热门文章

打赏
0
9 收藏
分享
打赏
0 评论
9 收藏
0
分享
返回顶部
顶部