本篇文章是基於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))