Python函数式编程指南(四):生成器
时间:2026-01-18
时间:2026-01-18
Python 函数式编程指南(四):生成器
生成器是迭代器,同时也并不仅仅是迭代器,不过迭代器之外的用途 实在是不多,所以我们可以大声地说:生成器提供了非常方便的自定 义迭代器的途径。 这是函数式编程指南的最后一篇,似乎拖了一个星期才写好,嗯…… 转载请注明原作者和原文地址:)4. 生成器(generator)4.1. 生成器简介
首先请确信,生成器就是一种迭代器。生成器拥有 next 方法并且行 为与迭代器完全相同,这意味着生成器也可以用于 Python 的 for 循 环中。另外,对于生成器的特殊语法支持使得编写一个生成器比自定 义一个常规的迭代器要简单不少, 所以生成器也是最常用到的特性之 一。 从 Python 2.5 开始,[PEP 342:通过增强生成器实现协同程序] 的实现为生成器加入了更多的特性, 这意味着生成器还可以完成更多 的工作。这部分我们会在稍后的部分介绍。4.2. 生成器函数 4.2.1. 使用生成器函数定义生成器
如何获取一个生成器?首先来看一小段代码:1 2 3 >>>def get_0_1_2(): ... yield 0 ... yield 1
我们定义了一个函数get_0_1_2,并且可以查看到这确实是函数类
型。但与一般的函数不同的是,get_0_1_2的函数体内使用了关键
字yield,这使得get_0_1_2成为了一个生成器函数。生成器函数
的特性如下:
1. 你的例子里生成器函数都没有参数,那么生成器函数可以带参数吗?
当然可以啊亲,而且它支持函数的所有参数形式。要知道生成器函数也是函数的一种:)
1 2 3 4 5
>>>def counter(start=0): ... while True: ... yield start ... start += 1 ...
2. 这是一个从指定数开始的计数器。 3. 既然生成器函数也是函数,那么它可以使用 return 输出返回值吗? 不行的亲,是这样的,生成器函数已经有默认的返回值——生成器了,你 不能再另外给一个返回值;对,即使是 return None 也不行。但是它可以 使用空的 return 语句结束。如果你坚持要为它指定返回值,那么 Python 将在定义的位置赠送一个语法错误异常,就像这样:1 2 3 4 5 6 >>>def i_wanna_return(): ... yield None ... return None ... File "<stdin>", line 3 SyntaxError: 'return' with argument inside generator
4. 好吧,那人家需要确保释放资源,需要在 try...finally 中 yield,这会是 神马情况?(我就是想玩你)我在 finally 中还 yield 了一次! Python 会在真正离开 try...finally 时再执行 finally 中的代码,而这里遗 憾地告诉你,暂停不算哦!所以结局你也能猜到吧!1 2 3 4 5 6 7 8 9 10 11 >>>def play_u(): ... try: ... yield 1 ... yield 2 ... yield 3 ... finally: ... yield 0 ... >>> for val in play_u(): print val, ... 1 2 3 0
有更多问题?请回复此文:)
4.3. 协同程序(coroutine)
协同程序(协程)一般来说是指这样的函数:
彼此间有不同的局部变量、指令指针,但仍共享全局变量;
可以方便地挂起、恢复,并且有多个入口点和出口点;
多个协同程序间表现为协作运行,如A的运行过程中需要B的结果才能继续执行。 协程的特点决定了同一时刻只能有一个协同程序正在运行(忽略多线
程的情况)。得益于此,协程间可以直接传递对象而不需要考虑资源
锁、或是直接唤醒其他协程而不需要主动休眠,就像是内置了锁的线
程。在符合协程特点的应用场景,使用协程无疑比使用线程要更方便。 从另一方面说,协程无法并发其实也将它的应用场景限制在了一个很
狭窄的范围,这个特点使得协程更多的被拿来与常规函数进行比较,而不是与线程。当然,线程比协程复杂许多,功能也更强大,所以我
建议大家牢牢地掌握线程即可:Python线程指南
这一节里我也就不列举关于协程的例子了,以下介绍的方法了解即可。 Python 2.5对生成器的增强实现了协程的其他特点,在这个版本中,生成器加入了如下方法:
5 6 7 8 9 10
... >>> r = repeater() >>>r.next() 0 >>>r.send(10) 10
2. *调用 send 传入非 None 值前,生成器必须处于挂起状态,否则将抛出异 常。不过,未启动的生成器仍可以使用 None 作为参数调用 send。 *如果使用 next 恢复生成器,yield 表达式的值将是 None。 3. close(): 这个方法用于关闭生成器。 对关闭的生成器后再次调用 next 或 send 将抛 出 StopIteration 异常。 4. throw(type, value=None, traceback=None): 这个方法用于在生成器内部 (生成器的当前挂起处, 或未启动时在定义处) 抛出一个异常。 *别为没见到协程的例子遗憾,协程最常见的用处其实就是生成器。4.4. 一个有趣的库:pipe
这一节里我要向诸位简要介绍 pipe。 pipe 并不是 Python 内置的库, 如果你安装了 easy_install,直接可以安装它,否则你需要自己下 载它:http:///pypi/pipe 之所以要介绍这个库, 是因为它向我们展示了一种很有新意的使用迭 代器和生成器的方式:流。pipe 将可迭代的数据看成是流,类似于 l inux,pipe 使用'|'传递数据流,并且定义了一系列的“流处理”函数 用于接受并处理数据流, 并最终再次输出数据流或者是将数据流归纳 得到一个结果。我们来
看一些例子。
第一个,非常简单的,使用 add 求和:1 2 3 >>> from pipe import * >>> range(5) | add 10
求偶数和需要使用到 where,作用类似于内建函数 filter,过滤 …… 此处隐藏:1567字,全部文档内容请下载后查看。喜欢就下载吧 ……
上一篇:三星级酒店大酒店营销策划方案
下一篇:审计案例参考答案