生成器(Generator)

回顾生成器表达式

条件和循环(包括迭代器、生成器)这篇博客里面我们简单的介绍过生成器表达式。回顾一下:

生成器表达式和列表解析式非常相似,基本语法基本相同;不过它并不真正创建列表,而是返回一个生成器。这个生成器在每次计算出一个条目后,把这个条目“yield(产生)”出来。生成器表达式使用了“延迟计算(lazy evaluation)”,所以在内存上更有效。

语法:

(expr for iter_var in iterable if cond_expr)

这里我们介绍的是生成器,它是一个带有yield表达式的函数。

生成器和迭代器的关系

生成器是一种特殊的迭代器。
迭代器中所有值都是已经生成好的,它解决的是“在所有值都存在的条件下,如何索引”的问题。生成器提出的动机是“在迭代中以某种方式生成下一个值并且返回”。它体现了函数式编程里的延迟计算的特点。

在使用迭代器的场景使用生成器对内存较为友好。

简单生成器

>>> def simpleGen():
        yield 1
        yield 'haha 2'


>>> generator = simpleGen()
>>> generator
<generator object simpleGen at 0x02ACD288>
>>> generator.next()
1
>>> generator.next()
'haha 2'
>>> generator.next()

Traceback (most recent call last):
  File "<pyshell#18>", line 1, in <module>
    generator.next()
StopIteration

分析

  • 第一次调用生成器的next方法时,生成器才开始执行生成器函数,直到遇到yield时暂停执行(挂起),并且yield的参数将作为此次next方法的返回值
  • 之后每次调用生成器的next方法,生成器将从上次暂停执行的位置恢复执行生成器函数,直到再次遇到yield时暂停,并且同样的,yield的参数将作为next方法的返回值
  • 如果当调用next方法时生成器函数结束(遇到空的return语句或是到达函数体末尾),则这次next方法的调用将抛出StopIteration异常

因为python的for循环next()函数调用以及有对StopIteration异常的处理,所以我们可以直接迭代生成器:

>>> for item in simpleGen():
        print item


1
haha 2
>>> 

增强的生成器

为什么说它增强了,因为它支持了协同程序(coroutine)

协同程序的定义

协同程序是一个独立的函数调用,它能够运行、暂停和挂起,也能够在暂停或挂起的地方开始继续运行。
它也支持调用者和被调用者之间的交流。

使用了协同的生成器

可以使用next()send()close()进行协同。
调用者通过send()给被调用者发送信息;你可以随时使用close()来关闭一个生成器。

看例子

>>> def counter(start_at=0):
        count = start_at
        while True:
            val = (yield count)  # 返回count(给next()),接收val(从send())
            if val is not None:
                count = val
            else:
                count += 1

>>> count = counter(5)  # 生成器被创建
>>> count.next()
5
>>> count.next()
6
>>> count.send(9)  # val变量被设置为9
9
>>> count.next()
10
>>> count.close()  # 生成器被关闭
>>> count.next()

Traceback (most recent call last):
  File "<pyshell#30>", line 1, in <module>
    count.next()
StopIteration

协程(协同程序)的特点决定了同一时刻只能有一个协同程序正在运行(忽略多线程的情况)。得益于此,协程间可以直接传递对象而不需要考虑资源锁、或是直接唤醒其他协程而不需要主动休眠,就像是内置了锁的线程。在符合协程特点的应用场景,使用协程无疑比使用线程要更方便。

从另一方面说,协程无法并发其实也将它的应用场景限制在了一个很狭窄的范围,这个特点使得协程更多的被拿来与常规函数进行比较,而不是与线程。当然,线程比协程复杂许多,功能也更强大


Ref
http://www.cnblogs.com/huxi/archive/2011/07/14/2106863.html
《Python核心编程》

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值