今天和大家聊聊 Python 的函数式编程特性. 所谓函数式编程, 就是指代码中每一块都是不可变的 (immutable), 都是由 pure function 的形式组成. 这里的 pure function 是指函数本身相互独立, 互不影响, 对于相同的输入, 总会有相同的输出. 也就是我们常说的没有副作用. 举个很简单的例子, 比如, 对于一个列表, 我想让列表中的元素值都变为原来的两倍, 我们可以写成下面的形式:
defmultiply_2(l):forindexinrange(0, len(l)):l[index] *=2returnl
这就不是一个 pure function, 因为列表中元素的值被改变了, 如果我调用 multiply_2() 这个函数多次, 那么每次得到的结果都不一样. 要想让其成为一个 pure function, 就得写成下面的形式, 重新创建一个新的列表并返回.
defmultiply_2_pure(l): new_list = []foriteminl:new_list.append(item *2)returnnew_list
函数式编程的优点主要在于其 pure function 和不可变的特性使得程序更加健壮, 易于 debug 和测试, 缺点主要在于限制多, 难写. 当然 Python 不同于其他一些语言, 比如 Scala, 他并不是一门纯粹的函数式编程语言, 但是 Python 也提供了一些函数式编程的特性, 值得我们了解和学习.
Python 主要提供了这么几个函数 Map, Filter 和 Reduce, 通常结合匿名函数 lambda 一起使用, 我逐一介绍一下:
对于 Map(function, iterable) 函数, 前面的例子提过, 他表示对 iterable 中的每个元素运用 function 这个函数, 最后返回一个新的可遍历的集合, 比如上面对列表中每个元素乘 2 用 map 可以表示为
l = [1, 2, 3, 4, 5]new_list = map(lambda x: x * 2, l)# [2, 4, 6, 8, 10]
我们再来看一下 Python 提供的函数式编程的接口的性能, 就以 Map 为例, 上述的例子还可以用 for 循环和 list comprehension 实现, 我们来比较一下他们的速度:
python3 -mtimeit -s'xs=range(1000000)' 'map(lambda x: x*2, xs)'输出结果: 2000000 loops, best of 5: 171 nsec per looppython3 -mtimeit -s'xs=range(1000000)''[x * 2 for x in xs]'输出结果: 5loops, best of5:62.9msec per looppython3 -mtimeit -s'xs=range(1000000)''l = []''for i in xs: l.append(i * 2)'输出结果: 5loops, best of5:92.7msec per loop
可以看到 map 是最快的, 因为 map 函数是直接由 C 语言写的, 运行时不需要通过 Python 解释器间接调用, 因此运行速度最快.
对于 Filter(function, iterable) 函数, 和 map 函数类似, function 同样表示一个函数对象, 表示对 iterable 中的每个元素使用 function 判断, 返回 True 或者 False, 最后将返回 True 的元素组成一个新的可遍历的集合, 比如我要返回一个列表中的所有偶数, 可以写成
l = [1, 2, 3, 4, 5]new_list = filter(lambda x: x % 2 == 0, l)# [2, 4]
对于 Reduce(function, iterable) 函数, 通常用于对一个集合做一些累积操作. function 同样是一个函数对象, 规定他有两个参数, 表示对 iterable 中的每个元素以及上一次调用后的结果运用 function 进行计算, 因此最后返回的是一个单独的数值, 比如, 我想要计算列表元素的乘积, 可以表示为:
l = [1, 2, 3, 4, 5]product = reduce(lambda x, y: x * y, l)# 1*2*3*4*5 = 120
类似的, Filter,Reduce 的功能也可以用 for 循环或者 list comprehension 来实现, 但是速度都不如 Filter 或者 Reduce.
通常来说, 如果你想对一个集合中的元素进行一些操作, 如果是一些非常简单的操作, 比如相加, 累积, 那么我们优先考虑 Map,Filter,Reduce 或者 list comprehension 的形式. 如果你在学习 Python 的过程当中有遇见任何问题, 可以加入我的 python 交流学习 qq 群: 250933691, 多多交流问题, 互帮互助, 群里有不错的学习教程和开发工具. 学习 python 有任何问题 (学习方法, 学习效率, 如何就业), 可以随时来咨询我
在这两者之中, 如果数据量非常大, 比如机器学习的应用, 那我们一般更倾向于函数式编程的表示, 因为效率更高, 如果数据量不多, 并且你想要自己的程序更加 Pythonic(Python 化), 那么运用 list comprehension 的情况也是很常见的. 如果你要对集合中的元素做一些比较复杂的操作, 考虑到代码的可读性, 这时我们通常会使用 for 循环, 因为更加清晰明了.
来源: http://www.jianshu.com/p/565a142c08fd