本篇文章是基于Joel Grus: Learning Data Science Using Functional Python视频的笔记。python
在Python中实现科里化的最佳方案是functools.partial
。例如如下例子:函数
# 通常版本 def add1(x): return add(1, x) # FP的版本 add1_functional = partial(add, 1)
这几个是常见的FP中处理列表的函数,在此不作介绍。工具
注意:Python这得
reduce
在functools
包中。指针
如下是个迭代器的例子:code
In [4]: a = [1,3,4] In [5]: b = iter(a) In [6]: next(b) Out[6]: 1 In [7]: next(b) Out[7]: 3 In [8]: next(b) Out[8]: 4 In [9]: next(b) --------------------------------------------------------------------------- StopIteration Traceback (most recent call last) <ipython-input-9-641a931447e8> in <module>() ----> 1 next(b) StopIteration:
迭代器的特色主要包括:视频
一次只用一个递归
只有须要时才会产生数据。ip
这两个特色保证了其惰性的特色,而另外一个好处是咱们能够构造无穷序列。内存
生成器所要生成的结果其实就是迭代器,以下:ci
def lazy_integers(n = 0): while True: yield n n += 1 xs = lazy_integers() [next(xs) for _ in range(10)] # [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] [next(xs) for _ in range(10)] # [10, 11, 12, 13, 14, 15, 16, 17, 18, 19]
上面的例子咱们能够看出,生成器在今生成了一个无穷长度的序列,因为其惰性咱们能够在有限内存之中储存这个无穷序列。
但值得注意的是,由于迭代器中的每一个值只能使用一次,就会获得一样语句不一样结果的例子(见上)。
squares = (x ** 2 for x in lazy_integers()) doubles = (x * x for x in lazy_integers()) next(squares) #0 next(squares) #1 next(squares) #4
咱们发现使用tuple能够直接改变迭代器中的每一个元素,这个特性很方便;但值得注意的是,不能写成列表的形式,否则输出值就不为惰性迭代器,就会引发内存外溢。
考虑一个文件之中出现某个单词(例如“prime”)的句子个数,采用函数式的方法,显然,以下:
with open("a.txt", "r") as f: lines = (line for line in f) prime_lines = filter(lambda line: "prime" in line.lower(), lines) line_count = len(list(prime_lines))
itertools
模块提供了大量用于操做迭代器的函数。
函数名 | 参数 | 做用 |
---|---|---|
count | [start=0], [step=1] | 输出无穷序列(start, start + step, start + 2 * step...) |
islice | seq, [start=0], stop, [step=1] | 输出序列的切片 |
tee | it, [n=2] | 复制序列,输出为多个相同序列组成的元组 |
repeat | elem, [n=forever] | 重复序列n次,输出为一个repeat元素 |
cycle | p | 无限重复cycle里的元素 |
chain | p, q, ... | 迭代p里的元素,而后再迭代q的元素,... |
accumulate | p, [func=add] | 返回(p[0], func(p[0], p[1]), func(func(p[0], p[1]), p[2])...) |
def take(n, it): """ 将前n个元素固定转为列表 """ return [x for x in islice(it, n)] def drop(n, it): """ 剔除前n个元素 """ return islice(it, n, None) # 获取序列的头 head = next # 获取除第一个元素外的尾 tail = partial(drop, 1)
此外,很常见的另外一个函数是得到一个递推的迭代器函数,即已知x, f,得到(x, f(x), f(f(x)),...)
def iterate(f, x): yield x yield from iterate(f, f(x))
注意,要防止mutation,就是说到底复制的是指针仍是指针表明的数,显然下面的写法是有问题的:
def iterate(f, x): while True: yield x x = f(x)
一个简单的避免方法是:
def iterate(f, x): return accumulate(repeat(x), lambda fx, _:f(fx))
iterate
def lazy_integers(): return iterate(add1, 0) take(10, lazy_integers())
def fib(n): if n == 0: return 1 if n == 1: return 1 return fib(n - 1) + fib(n - 2) [fib(i) for i in range(10)]
def fibs(): a, b = 0, 1 while True: yield b a, b = b, a + b take(10, fibs())
def fibs(): yield 1 yield 1 yield from map(add, fibs(), tail(fibs())) take(10, fibs())
def fibs(): yield 1 yield 1 fibs1, fibs2 = tee(fibs()) yield from map(add, fibs1, tail(fibs2))