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
。