理解新概念

Python V2.2 中引入了迭代器的思想。唔,这并不十分正确;这种思想的“苗头”早已出现在较老的函数 xrange() 以及文件方法 .xreadlines() 中了。通过引入 yield 关键字,Python 2.2 在内部实现的许多方面推广了这一概念,并使编程定制迭代器变得更为简单( yield 的出现使函数转换成生成器,而生成器反过来又返回迭代器)。

迭代器背后的动机有两方面。将数据作为序列处理通常是最简单的方法,而以线性顺序处理的序列通常并不需要都同时实际 存在

x*() 前兆提供了这些原理的清晰示例。如果您想对某操作执行成千上万次,那么执行您的程序可能要花些时间,但该程序一般不需要占用大量内存。同样,对于许多类型的文件,可以一行一行地处理,且不需要将整个文件存储在内存中。最好对其它所有种类的序列也进行惰性处理;它们可能依赖于通过通道逐步到达的数据,或者依赖于一步一步执行的计算。

大多数时候,迭代器用在 for 循环内,就象真正的序列那样。迭代器提供了 .next() 方法,它可以被显式调用,但有百分之九十九的可能,您所看到的是以下行:

for x in iterator:do_something_with(x)

在对 iterator.next() 进行幕后调用而产生 StopIteration 异常时,该循环就被终止。顺便说一下,通过调用 iter(seq) ,实际序列可以被转换成迭代器 - 这不会节省任何内存,但是在下面讨论的函数中它会很有用。


回页首

Python 不断发展的分裂性格

Python 对函数编程(FP)的观点有点相互矛盾。一方面,许多 Python 开发人员轻视传统的 FP 函数 map()filter()reduce() ,常常建议使用“列表理解”来代替它们。但完整的 itertools 模块恰恰是由与这些函数类型完全相同的函数组成的,只不过这些函数对“惰性序列”(迭代器)操作,而不是对完整的序列(列表,元组)操作。而且,Python 2.3 中没有任何“迭代器理解”的语法,这似乎与列表理解拥有一样的动机。

我猜想 Python 最终会产生某种形式的迭代器理解,但这取决于找到合适于它们的自然语法。同时,在 itertools 模块中,我们拥有大量有用的组合函数。大致地,这些函数中的每一个都接受一些参数(通常包含一些基础迭代器)并返回一个新迭代器。例如,函数 ifilter()imap()izip() 都分别直接等同于缺少词首 i 的内置函数。


回页首

缺少的等价函数

itertools 中没有 ireduce() ,尽管按道理很自然地应该有这个函数;可能的 Python 实现是:

清单 1. ireduce() 的样本实现

def ireduce(func, iterable, init=None):if init is None:iterable = iter(iterable)curr = iterable.next()else:curr = initfor x in iterable:curr = func(curr, x)yield curr

ireduce() 的用例类似于 reduce() 的用例。例如,假设您想要添加某个大型文件所包含的一列数字,但是当满足一个条件时就停止。您可以使用以下代码来监控正在计算的合计数:

清单 2. 添加并合计一列数

from operator import add
from itertools import *
nums = open('numbers')
for tot in takewhile(condition, ireduce(add, imap(int, nums)):print "total =", tot

一个更实际的示例可能类似于将事件流应用于有状态对象上,例如应用到 GUI 窗口小部件上。但是即使是上述简单示例也显示了迭代器组合器的 FP 风格。


回页首

基本迭代器工厂

itertools 中的所有函数都可以用纯 Python 轻松地实现为生成器。在 Python 2.3+ 中包含该模块的要点是为一些有用的函数提供标准行为和名称。尽管程序员可以编写他们自己的版本,但是每个人实际创建的变体都会有点不兼容。但是,另一方面是要以高效率的 C 代码实现迭代器组合器。使用 itertools 函数将比编写您自己的组合器稍微快一些。标准文档显示了每个 itertools 函数的等价纯 Python 实现,所以不需要在本文中重复这些内容了。

itertools 中的函数再基本不过了 - 而且命名也完全不同 - 这样从该模块导入所有名称可能就有意义了。例如,函数 enumerate() 可能明显地出现在 itertools 中,但是它在 Python 2.3+ 中却是一个内置函数。值得注意的是,您可以用 itertools 函数很方便地表达 enumerate()

from itertools import *
enumerate = lambda iterable: izip(count(), iterable)

让我们首先看一下几个 itertools 函数,它们 没有将其它迭代器作为基础,而完全是“从头”创建迭代器。 times() 返回一个多次产生同一对象的迭代器;在本质上,这一能力比较有用,但它确实可以很好地替代使用过多的 xrange() 和索引变量,从而可以简单地重复一个操作。即,不必使用:

for i in xrange(1000):do_something()

您现在就可以使用更中性的:

for _ in times(1000):do_something()

如果 times() 只有一个参数,那么它只会重复产生 None 。函数 repeat() 类似于 times() ,但它无界地返回同一对象。不管是在包含独立 break 条件的循环中还是在象 izip()imap() 这样的组合器中,这个迭代器都很有用。

函数 count() 有点类似于 repeat()xrange() 的交叉。 count() 无界地返回连续整数(以可选的参数为开始)。但是,如果 count() 当前不支持溢出到现在正确的 longs,那么您可能还是要使用 xrange(n,sys.maxint) ;它并不是完全无界的,但是对于大多数用途,它实际上是一回事。类似于 repeat()count() 在其它迭代器组合器内部特别有用。


回页首

组合函数

我们已经顺便提到了 itertools 中的几个实际组合函数。 ifilter()izip()imap() 的作用就象您会期望从它们相应的序列函数上获得的作用。 ifilterfalse() 很方便,所以您不需要去掉 lambdadef 中的谓词函数(而且这还节省了大量的函数调用开销)。但是在功能上,您可以将 ifilterfalse() 定义为(大致的情况,忽略了 None 谓词):

def ifilterfalse(predicate, iterable):return ifilter(lambda predicate: not predicate, iterable)

函数 dropwhile() 和函数 takewhile() 根据谓词对迭代器进行划分。 dropwhile() 在直到满足某个谓词 之前忽略所产生的元素, takewhile() 在满足某个谓词 就终止。 dropwhile() 跳过迭代器的不定数目的初始元素,所以它可能直到某个延迟后才开始迭代。 takewhile() 马上开始迭代,但是如果被传入的谓词变为真,那么就终止迭代器。

函数 islice() 基本上就是列表分片的迭代器版本。您可以指定开始、停止和步长,就象使用常规的片。如果给定了开始,那么会删除大量元素,直到被传递的迭代器到达满足条件的元素为止。这是另一个我认为可以对 Python 进行改进的情形 - 迭代器最好只识别片,就象列表所做的(作为 islice() 行为的同义词)。

最后一个函数 starmap()imap() 基础上略微有些变化。如果这个作为参数传递的函数获取多个参数,那么被传递的 iterable 会产生大小适合的元组。这基本上与包含多个被传入 iterable 的 imap() 相同,只不过它包含先前与 izip() 结合在一起的 iterables 集合。


回页首

深入探讨

itertools 中包含的函数是一个很好的开始。不使用其它函数,只用这些函数就可以让 Python 程序员更轻松地利用和组合迭代器。一般说来,迭代器的广泛使用对 Python 的未来无疑是很重要的。但是除了过去所包含的内容以外,我还要对该模块的将来更新提几点建议。您可以立即很方便地使用这些函数 - 当然,如果它们是后来被包含进来的,那么名称或接口细节会有所不同。

一种可能会很通用的类别是一些将多个 iterable 作为参数,随后从每个 iterable 产生单独元素的函数。与此相对照的是, izip() 产生元素元组,而 imap() 产生从基本元素计算而来的值。我头脑中很清晰的两个安排是 chain()weave() 。第一个在效果上类似于序列并置(但是有点惰性)。即,在您可能使用的纯序列中,例如:

for x in ('a','b','c') + (1, 2, 3):do_something(x)

对于一般的 iterables,您可以使用:

for x in chain(iter1, iter2, iter3):do_something(x)

Python 实现是:

清单 3. chain() 的样本实现

def chain(*iterables):for iterable in iterables:for item in iterable:yield item

使用 iterables,您还可以通过使它们分散排列来组合几个序列。还没有任何对序列执行这样相同操作的内置语法,但是 weave() 本身也非常适用于完整的序列。下面是可能的实现(Magnus Lie Hetland 提出了 comp.lang.python 的类似函数):

清单 4. weave() 的样本实现

def weave(*iterables):"Intersperse several iterables, until all are exhausted"iterables = map(iter, iterables)while iterables:for i, it in enumerate(iterables):try:yield it.next()except StopIteration:del iterables[i]

让我来演示一下 weave() 的行为,因为从实现上看不是很明显:

>>> for x in weave('abc', xrange(4), [10,11,12,13,14]):
...    print x,
...
a 0 10 b 1 11 c 2 12 13 3 14

即使一些迭代器到达终点,但其余迭代器会继续产生值,直到在某一时刻产生了所有可用的值为止。

我将另外只提出一个可行的 itertools 函数。提出这个函数主要是受到了构思问题的函数编程方法的启发。 icompose() 与上面提出的函数 ireduce() 存在某种对称。但是在 ireduce() 将值的(惰性)序列传递给某个函数并产生每个结果的地方, icompose() 将函数序列应用于每个前趋函数的返回值。可以把 ireduce() 用于将事件序列传递给长期活动的对象。而 icompose() 可能将对象重复地传递给返回新对象的赋值函数。第一种方法是相当传统的考虑事件的 OOP 方法,而第二种的思路更接近于 FP。

以下是可能的 icompose() 实现:

清单 5. icompose() 的样本实现

def icompose(functions, initval):currval = initvalfor f in functions:currval = f(currval)yield currval

结束语

迭代器 - 被认为是惰性序列 - 是功能强大的概念,它开启了 Python 编程的新样式。但是在只把迭代器当作数据源与把它作为一种序列来考虑之间存在着微妙的差别。这两种想法本质上哪一种都不见得比另一种更正确,但是后者开创了操作编程事件的一种组合性的简略表达方法。 itertools 中的组合函数(尤其是它可能产生的一些类似于我建议的函数)接近于编程的声明样式。对我而言,这些声明样式一般都更不易出错且更强大。

合并和分离iterators

chain

使用chain将多个iterators合并成一个itertator。

# -*- coding: cp936 -*-

from itertools import *

for i in chain([1, 2, 3], ['a', 'b', 'c']):

print i

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

结果:

>>>

1

2

3

a

b

c

izip

izip() 将多个 iterators 迭代的内容混合成一个元组,并返回这个元组的迭代器,和zip()类似。

# -*- coding: cp936 -*-

from itertools import *

for i in izip([1, 2, 3], ['a', 'b', 'c']):

    print i

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

>>>

(1, 'a')

(2, 'b')

(3, 'c')

islice

看PyMOTW的例子之前不了解count是干啥的,help一下发现也是itertools module里的,作用就是从一个数(默认为零)开始迭代。

islice接受一个iterator作为输入,返回指定的条目。和slice类似,其参数格式为(起始索引, 结束索引, 步伐)。例如:

# -*- coding: cp936 -*-

from itertools import *

print 'By tens to 100:'

for i in islice(count(), 0, 100, 10):

    print i

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

>>>

By tens to 100:

0

10

20

30

40

50

60

70

80

90

tee

接受一个iterator,返回多个(两个)与输入iterator相同的iterators。例如:

# -*- coding: cp936 -*-

from itertools import *

r = islice(count(), 5)

i1, i2 = tee(r)

for i in i1:

    print 'i1:', i

for i in i2:

    print 'i2:', i

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

>>>

i1: 0

i1: 1

i1: 2

i1: 3

i1: 4

i2: 0

i2: 1

i2: 2

i2: 3

i2: 4

在对一个iterator调用了tee以后,对这个iterator的迭代会影响到tee所产生的那些iterators。

转换输入

imap

imap接受一个函数,一个或者多个iterators作为输入,并将函数应用到各个iterators引用的元素上,返回结果。

# -*- coding: cp936 -*-

from itertools import *

#一个iterator

print 'Doubles:'

for i in imap(lambda x:2*x, xrange(5)):

    print i

#多个iterators

print 'Multiples:'

for i in imap(lambda x,y:(x, y, x*y), xrange(5), xrange(5,10)):

    print '%d * %d = %d' % i

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

>>>

Doubles:

0

2

4

6

8

Multiples:

0 * 5 = 0

1 * 6 = 6

2 * 7 = 14

3 * 8 = 24

4 * 9 = 36

starmap

starmap()函数和imap类似,不同之处在于只接受一个iterator作为参数,并且使用函数调用时候的*语法将iterator迭代的内容展开。假设传入的函数为f、迭代器为i,则相当于调用f(*i)。

# -*- coding: cp936 -*-

from itertools import *

values = [(0, 5), (1, 6), (2, 7), (3, 8), (4, 9)]

for i in starmap(lambda x,y:(x, y, x*y), values):

    print '%d * %d = %d' % i

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

>>>

0 * 5 = 0

1 * 6 = 6

2 * 7 = 14

3 * 8 = 24

4 * 9 = 36

产生新值

count()不断地产生整数,cycle()不断地循环几个给定的输入,repeat()不断地重复一个输入,它们的返回值都是iterator。

过滤

dropwhile()接受一个测试函数和一个iterator作为输入,对iterator迭代的内容应用测试函数,当测试函数第一次返回True之后,迭代器开始返回其后的内容。takewhile()和dropwhile()相反。

ifilter会对每一个元素应用测试函数,为True的就返回迭代的内容。ifilterfalse()和它相反

转载于:https://www.cnblogs.com/yd1227/archive/2011/03/18/1988399.html

[转]可爱的 Python:: 使用 itertools 模块中的组合函数相关推荐

  1. Python itertools 模块中的 product 函数

    product 用于求多个可迭代对象的笛卡尔积 (Cartesian Product) 可用于同时历遍循环多个对象 from itertools import productl1 = ['a', 'b ...

  2. python 彩票排列组合_对福彩3D号码进行排列组合为例学习Python的itertools模块的用法...

    这里我们以对福彩3D号码进行排列组合为例学习Python的itertools模块的用法.首先我们选择心仪的号码.比如我们选择4,5,7,8 第一种我们只要组六的组合.代码如下 import itert ...

  3. python init main_python 模块中的 __init__.py __main__.py

    python中文件夹想作为一个模块被引用,则在文件夹内必须要包含 __init__.py 文件,即使此文件为空. 如果此模块想要运行则必须要包含 __main__.py 文件.接下来说下两个文件起到的 ...

  4. Python的collections模块中namedtuple结构使用示例

    namedtuple顾名思义,就是名字+元组的数据结构,下面就来看一下Python的collections模块中namedtuple结构使用示例 namedtuple 就是命名的 tuple,比较像 ...

  5. python scipy.stats.norm.cdf_python的scipy.stats模块中正态分布常用函数总结

    python的scipy.stats模块是连续型随机变量的公共方法,可以产生随机数,通常是以正态分布作为scipy.stats的基本使用方法.本文介绍正态分布的两种常用函数:1.累积概率密度函数sta ...

  6. Python:numpy库中的一些函数简介、使用方法之详细攻略

    Python:numpy库中的一些函数简介.使用方法之详细攻略 目录 numpy库中的一些函数简介.使用方法 1.np.concatenate() 1.1.函数案例 1.2.函数用法 numpy库中的 ...

  7. [转载] python数学计算模块之math常用函数学习使用

    参考链接: Python中的分数模块Fraction 因为最近经常使用到math模块中的常用函数,但是又记不住所有的函数名称,在今天结束之前花一点时间总结一下吧,很多都用过,只有几个角度计算函数不常用 ...

  8. python中全组合函数(combinations)与全排列函数(permutations)

    最近写代码时遇到排列组合问题,发现python中的itertools库用起来比较方便.itertools库中的permutations函数可以输出可迭代对象的全排列情况,而combinations函数 ...

  9. python中全组合函数(combinations)与全排列函数(permutations)的介绍与参数说明

    概要:在平常的编程过程中,往往需要面对排列组合的应用情况,而每次自己编写相应的函数会耗费较多的时间,而python中的itertools库就为我们解决了这个小问题.itertools库中的permut ...

  10. Iar环境c语言调用汇编函数,如何在IAR EWARM中通过内联汇编程序在另一个模块中调用C函数?...

    我在硬故障处理程序中有一些程序集.程序集基本上是为了传递当前堆栈指针作为参数(在R0中).它看起来像这样...如何在IAR EWARM中通过内联汇编程序在另一个模块中调用C函数? __asm(&quo ...

最新文章

  1. linux下有关phy的命令,linux – 如何为Debian安装b43-lpphy-installer?
  2. python 目录下的__init__.py
  3. 华南理工大学网络教育计算机答案,计算机应用基础--随堂练习2019春华南理工大学网络教育答案...
  4. roscore尚未安装 问题解决方案
  5. Hinton神经网络公开课编程练习3 Optimization and generalization
  6. 如何通过调试找到自己需要的ABAP增强
  7. 了解js基础知识中的作用域和闭包以及闭包的一些应用场景,浅析函数柯里化
  8. mysql数据库突然连不上了_mysql数据库突然连接不上去
  9. 腾讯视频电脑版下载_腾讯视频~如何用腾讯视频
  10. [论文阅读][深度学习-三维重建]Single-Shot 3D Shape Reconstruction Using Structured Light and CNN
  11. B 站 Up主自制秃头生成器,圆你一个秃头梦?
  12. unix系统安装及应用
  13. 深圳免费旅游景点大全|深圳旅游攻略(下)
  14. linux bluefish制作网页,基于Linux文本模式的网页编辑器Bluefish
  15. laravel 发送邮件
  16. html内部css调节背景图片的大小,css中怎么改变背景图片大小?
  17. JSON与事件和BOM
  18. 创建一个Date类,具有三个整型成员变量year,month,day,具有三个成员方法setDate,isLeapYear,print
  19. Dell H300/6i/6iR/H700/H800阵列卡配置(转)
  20. 车灯线光源的优化设计matlab,车灯线光源的优化设计

热门文章

  1. ePass.CreateFile
  2. oracle试图怎么使用,oracle 视图的介绍和使用
  3. 富士相机设置传原图_富士XT4 多位摄影师试用体验报告
  4. 关于Time.deltatTime的理解
  5. markdown快速创建表格及内容工具
  6. 单片机有什么功能,看完一定有收获
  7. Collectors.toList()
  8. 【渝粤教育】国家开放大学2018年春季 8668-21T汽车涂装技术(A) 参考试题
  9. 操作系统原理(三)进程管理、线程、并发和并行
  10. ACM 学习笔记(四) 数据结构之列表、数组、栈、队列