Guido 非常不喜歡lambda
、map
、filter
以及reduce
這幾個函數語言程式設計中的函式,他比較喜歡使用表推導。而且出於防止濫用的考慮,lamdba
在Python中”享受”到了在其他語言中未曾遇到過的限制。
我個人也很喜歡錶推導,不僅僅是速度快,而且看上去更pythonic,那麼,上面說的幾個函式是不是都可以用表推導代替呢?來做個試驗。
map
最基本的lambda
就是一個接受引數返回值的匿名函式,沒有涉及到列舉,就不單獨說了。直接把lambda
和map
組合起來用,map
的作用是將一個函式對映到一個列舉型別上。比如求一個列表中所有值的三次方:
1 2 3 |
>>>l = [1, 2, 3] >>>list(map(lambda x: x**3, l)) [1, 8, 27] |
使用表推導:
1 2 3 |
>>>l = [1, 2, 3] >>>[x**3 for x in l] [1, 8, 27] |
沒什麼好說的, 表推導更簡潔。注意map
外面用了list這是Python3中的語法,因為在Python3中,map
和filter
都從返回列表更改為返回迭代器了。
filter
filter
返回可迭代物件傳入function後返回值為True的item。
例如,返回一個列表中只含有字母的元素:
1 2 3 |
>>>l = ['H2O', 'HO', 'HNO3', 'CO'] >>>list(filter(lambda x: x.isalpha(), l)) ['HO', 'CO'] |
使用表推導
1 2 3 |
>>>l = ['H2O', 'HO', 'HNO3', 'CO'] >>>[x for x in l if x.isalpha()] ['HO', 'CO'] |
嗯,看上去還是表推導更好看,更容易理解
reduce
reduce
稍微複雜一些,reduce
是一種類似向左摺疊列表的操作,按照可迭代物件的順序迭代呼叫函式。並且要求函式接受兩個引數。如果有第三個引數,則表示初始值。
一個簡單的例子,求10的階乘:
1 2 3 |
>>>from functools import reduce # 在Python3中,reduce()已經從全域性名稱空間中移除,放置在functools模組中 >>>reduce(lambda x, y: x*y, range(1, 10)) 362880 |
reduce
還接受第三個引數,作為初始值,有時候我們是一定需要第三個引數的,例如在一段文字中查詢某個單詞出現的次數:
1 2 3 4 |
>>>from functools import reduce >>>sen = 'I scream, you scream, we all scream for ice-cream!' >>>reduce(lambda a, x: a + x.count('cream'), sen.split(), 0) 4 |
如果不使用預設值,第一個值就是大寫字母’I’,顯然不能用於計算出現的次數。
這種左乘的迭代操作,並不適合用表推導來實現。
當然為了表示我對錶推導的支援,我把上面第二個reduce
例子,用表推導實現了一下:
1 2 3 |
>>>sen = 'I scream, you scream, we all scream for ice-cream!' >>>[i for i in sen.split() if 'cream' in i].__len__() 4 |
然而這並沒有什麼luan用,因為迭代求和求乘積的,還是reduce更好用。
apply
apply在Python3中已經被移除了,統一使用*
將列表中的值作為引數傳入。
結論
綜上,表推導可以完全替代map
和filter
並且更簡潔,但是不適用於reduce
。