可迭代器(iterable),不仅限于list/str等,还包括任何包含有yield关键字的函数,后者未必有规律的迭代特征。标准库中的itertools包提供了更加灵活的产生迭代器的工具,这些工具的输入大都是已有的迭代器函数的封装,并且itertools给出的函数都是针对广义迭代器而言。而len()等函数是针对狭义迭代器,即sequence(i.e. str, list, tuple)而言的。
以内置函数range()为例,执行结果会是一次性计算好整个序列。这对于很长的序列来说会比较耗时,甚至带来性能问题。因而,python还提供了内置函数,提供了惰性求值版本,那就是xrange()。它利用yield特性,第一次执行时仅仅返回迭代器,不到用时是不会求值的。
实际上,itertools提供的函数都是惰性的,并且给原内置函数都重写了惰性版本。如imap()对于内置的map()。
扩展库Pipe则对内置函数和部分itertools进行了封装,提供了类似unix bash下的管道式调用风格,更接近人类从左到右的阅读习惯,使得代码更加优雅。其他动态语言,如ruby, c#-lambda java8-lambda也都提供了类似的链式调用形式。
另外,也提供了@Pipe装饰器,可以非常方便地扩展出自己的管道函数,或者继续封装其他itertools中的有用函数。
这里是Pipe官方给出的例子,用管道函数式编程解出https://projecteuler.net/中的三道题目:
| 1 | 
 | 
注意:所有惰性求值的迭代器,都是只能求值一次的,如果再次求值会什么也得不到,因为yield堆栈已经走到底,无法回头。因此,当要对惰性迭代器重复使用时,必须故意地提前将其求值展开,或者利用itertools.tee来克隆一个迭代器。
输入输出
| 1 | "42" | stdout # 输出到标准输出 >>> 42 | 
数学运算
| 1 | [1, 2, 3, 4] | concat("#") # 连接字符串 >>>'1#2#3#4' | 
组合工具
| 1 | (1, 2, 3, 4, 5, 6, 7, 8, 9) \ | 
产生无限序列
| 1 | itertools.count(5, 2) # 从5开始的整数循环器,每次增加2,即5, 7, 9, 11, 13, 15 ...步长默认为1 | 
序列运算
| 1 | xrange(5) | aggregate(lambda x, y: x + y, initializer=0) # 同内置reduce函数 >>> 10 | 
其他惰性求值版本函数
| 1 | itertools.imap(pow, (1,2,3),(1,2,3)) | as_list # map的惰性版本 >>> [1, 4, 27] | 
自定义Pipe管道函数
| 1 | from pipe import * |