functional programming

函数式编程的一大特性就是:可以把函数当作变量来使用,比如将函数赋值给其他变量、把函数作为参数传递给其他函数、函数的返回值也可以是一个函数等等。

高阶函数

在函数式编程中,我们可以把将函数当作变量一样自由使用。一个函数接收另一个函数作为参数,这种函数称之为高阶函数(Higher-order-Functions)。
看一个简单的例子:

1
2
def func(g,arr):
return [g(x) for x in arr]

上面的代码中,func是一个高阶函数,它接收两个参数,第一个参数是函数,第二参数是数组,func的功能是将函数g逐个作用于数组arr上,并返回一个新的数组,比如,这样:

1
2
3
4
5
6
7
8
def double(x):
return 2 * x

def square(x):
return x * x

arr1 = func(double, [1, 2, 3, 4])
arr2 = func(square, [1, 2, 3, 4])

不难判断出,arr1 是 [2, 4, 6, 8],arr2 是 [1, 4, 9, 16]。

匿名函数

在 Python 中,我们使用 def 语句来定义函数,比如:

1
2
def double(x):
return 2 * x

除了用上面的方式定义函数,Python 还提供了一个关键字 lambda,让我们可以创建一个匿名函数,也就是没有名称的函数。它的形式如下:

1
lambda 参数: 表达式

关键字 lambda 说明它是一个匿名函数,冒号 : 前面的变量是该匿名函数的参数,冒号后面是函数的返回值,注意这里不需使用 return 关键字。
我们将上面的double函数改成一个匿名函数,如下:

1
lambda x: 2 * x

那怎么调用匿名函数呢?可以直接使用:

1
2
>>> (lambda x : 2 * x)(8)
16

由于匿名函数本质是一个函数对象,也可以将其赋值给另一个变量,再由该变量来调用函数,如下:

1
2
3
4
5
6
>>> f = lambda x : 2 * x
>>> f
<function <lambda> at 0x7f3da14ee848>
>>> f(8)
16
>>>

使用场景
lambda 函数一般适用于创建一些临时性的,小巧的函数。比如上面的 double 函数,我们当然可以使用 def 来定义,但使用 lambda 来创建会显得很简洁,尤其是在高阶函数的使用中。

看一个例子:

1
2
def func(g, arr):
return [g(x) for x in arr]

现在给一个列表[1,2,3,4],利用上面的函数,对列表中的元素加1,返回一个新的列表,可以这样用:

1
2
3
def add_one(x):
return x + 1
arr = func(add_one, [1,2,3,4])

这样做没什么错,可是 add_one 这个函数太简单了,使用 def 定义未免有点小题大作,我们改用 lambda:

1
arr = func(lambda x: x + 1, [1,2,3,4])

map

map函数的使用形式如下:

1
map(function, sequence)

解释:对sequence中的item依次执行function(item),并将结果组成一个List返回,也就是:

1
[fuctiona(item1), function[item2],function[item3],...]

看一些简单的例子。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
>>> def square(x):
... return x * x

>>> map(square, [1, 2, 3, 4])
[1, 4, 9, 16]

>>> map(lambda x: x * x, [1, 2, 3, 4]) # 使用 lambda
[1, 4, 9, 16]

>>> map(str, [1, 2, 3, 4])
['1', '2', '3', '4']

>>> map(int, ['1', '2', '3', '4'])
[1, 2, 3, 4]

reduce

reduce函数的使用形式如下:

1
reduce(fuction, sequence[, initial])

解释:先将sequence的前两个item传给function,即funtion(item1,item2),函数的返回值和sequence的下一个item再传给function,即function(function(item1,item2),item3),如此迭代,直到sequence没有元素,如果有initial,则作为初始值调用。
也就是说:

1
reduce(f,[x1,x2,x3,x4]) = f(f(f(x1, x2), x3), x4)

再看一些例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
>>> reduce(lambda x, y: x * y, [1, 2, 3, 4])  # 相当于 ((1 * 2) * 3) * 4
24
>>> reduce(lambda x, y: x * y, [1, 2, 3, 4], 5) # ((((5 * 1) * 2) * 3)) * 4
120
>>> reduce(lambda x, y: x / y, [2, 3, 4], 72) # (((72 / 2) / 3)) / 4
3
>>> reduce(lambda x, y: x + y, [1, 2, 3, 4], 5) # ((((5 + 1) + 2) + 3)) + 4
15
>>> reduce(lambda x, y: x - y, [8, 5, 1], 20) # ((20 - 8) - 5) - 1
6
>>> f = lambda a, b: a if (a > b) else b # 两两比较,取最大值
>>> reduce(f, [5, 8, 1, 10])
10

filter

filter函数用于果率元素,它的形式如下:

1
filter(function, sequence)

解释:将 function 依次作用于 sequnce 的每个 item,即 function(item),将返回值为 True 的 item 组成一个 List/String/Tuple (取决于 sequnce 的类型,python3 统一返回迭代器) 返回。

看一些例子。

1
2
3
4
5
6
7
8
9
10
>>> even_num = list(filter(lambda x: x % 2 == 0, [1, 2, 3, 4, 5, 6]))
>>> even_num
[2, 4, 6]
>>> odd_num = list(filter(lambda x: x % 2, [1, 2, 3, 4, 5, 6]))
>>> odd_num
[1, 3, 5]
>>> filter(lambda x: x < 'g', 'hijack')
'ac' # python2
>>> filter(lambda x: x < 'g', 'hijack')
<filter object at 0x1034b4080> # python3