Python中的高阶函数
在熟悉了Python基础知识后,我们已经可以做一些脚本开发,或者简单的程序。然而,当我们开发较为复杂的程序时,仅使用基础知识内容就会显得比较吃力。这时,了解Python中的一些高级特性会使我们的开发过程变得简单和快乐。
在函数式编程中,我们可以将函数当做变量一样自由使用。一个函数接收另一个函数作为参数,这种函数称之为高阶函数(Higher-order-Functions)。
看一个简单的例子:
1 | def func(g, arr): |
上面的代码中func
是一个高阶函数,它接收两个参数,第一个参数是函数,第二个参数是数组,func
的功能是将函数g逐个作用于数组arr上,并返回一个新的数组。比如,我们可以这样用:
1 | def double(x): |
说到高阶函数,就不得不提到闭包,这里介绍一下Python中闭包的定义:
如果在一个内部函数里,对外部作用域(但不是全局作用域)的变量进行引用,那么内部函数就被认为是闭包(closure)。
就拿此例来说,内部函数double
中包含了对函数func
中局部变量list
的引用,这就是闭包。
map
reduce
filter
sorted
是Python中较为常用的内置高阶函数,它们为函数式编程提供了不少便利。
说明:本文介绍的内置高阶函数的定义可能会因为Python版本的不同而有所不同,文章以Python3.x版本中的定义为标准。
map
map
函数的使用形式如下:
1 | map(function, iterable, ...) |
注意:这里函数一定要作为map的第一个参数,而不是第二个参数,否则会产生报错。
解释:function函数会作用于可迭代对象的每一个元素,生成结果,并返回一个迭代器。更加具体一点说就是map
函数接收两个参数,一个是函数,一个是Iterable,map
将传入的函数依次作用到Iterable的每个元素,并把结果作为新的Iterator返回。
举例说明,比如我们一个函数f(x)=x^2,要把这个函数作用在一个list[1, 2, 3, 4, 5, 6, 7, 8, 9]上,就可以用map()
实现。
现在,我们用Python代码实现:
1 | def f(x): |
map
传入的第一个参数是f
,即函数对象本身。由于结果r
是一个Iterator,Iterator是惰性序列,因此需要通过list()
函数让它把整个序列都计算出来并返回一个list。
你可能会想,不需要map
函数,写一个循环,也可以计算出结果:
1 | L = [] |
的确可以,但是,从上面的循环代码,能一眼看明白“把f(x)作用在list的每一个元素并把结果生成一个新的list”吗?明显可读性就差了很多。
所以,map
作为高阶函数,体现了Python的设计原则优雅、明确、简单,事实上它把运算规则抽象化。因此,我们不但可以计算简单的f(x)=x2,还可以计算任意复杂的函数,比如,把list中的所有数字转化为字符串格式:
1 | 1, 2, 3, 4])) list(map(str, [ |
只需一行代码。
看一些简单的例子:
1 | def square(x): |
再来看个复杂一点例子:
1 | def double(x): |
最后我想要说明一点,迭代器有一个特点,就是所有的迭代器对象都可以作为next()
内置函数的参数调用,每调用一次,就按角标顺序返回一个值,还是用代码讲吧:
1 | iter = map(lambda x: x * x, [1, 2, 3, 4]) |
reduce
reduce
函数的使用形式如下:
1 | reduce(function, iterable[, initializer]) |
解释:reduce
函数必须接受两个参数,先将iterable的前两个item传给function,即function(item1, item2),函数的返回值和iterable的下一个item再传给function,即function(function(item1, item2), item3),如此迭代,直到iterable没有元素,如果有initializer,则作为初始值调用。
也就是说:
1 | reduce(f, [x1, x2, x3, x4]) = f(f(f(x1, x2), x3), x4) |
看一些例子,就能很快理解了。
1 | from functools import reduce |
filter
filter
函数用于过滤元素,它的使用形式如下:
1 | filter(function, iterable) |
解释:和map
类似,filter
也接收一个函数和一个序列。但和map
不同的是,filter
把传入的函数依次作用于每个元素,然后根据返回值是True还是False决定保留还是丢弃该元素。将function依次作用于iterable的每个item上,即function(item),用function返回值为True的item构成iterator作为filter
的最终返回值。
看一些例子。
1 | lambda x: x % 2 == 0, [1, 2, 3, 4, 5, 6])) even_num = list(filter( |
可见用filter
这个高阶函数,关键在于正确实现一个“筛选”函数。
注意到filter
函数返回的同样是一个Iterator,也就是一个惰性序列,所以要强迫filter
完成计算结果,需要用list()
函数获得所有结果。
sorted
sorted
函数用于对list进行排序,它的使用形式如下:
1 | sorted(iterable, *, key=None, reverse=False) |
解释:sorted
有两个可选参数,必须指定为关键字参数。将key指定的函数作用于iterable的每一个元素上,并根据key函数返回的结果进行排序,最终返回一个新的排序列表。key默认值为None,即直接比较元素大小。
reverse是一个布尔值。如果设置为True,则列表元素将按照比较结果相反的方式进行排序。
看一些例子:
1 | 36, 5, -12, 9, -21]) sorted([ |
从上述例子可以看出,高阶函数的抽象能力是非常强大的,而且核心代码可以保持得非常简洁。
小结
- 可接受其他函数作为参数的函数称为高阶函数;
map
reduce
filter
sorted
为函数式编程提供了不少便利,可使代码变得更简洁;- 通过
map()
来对Iterable中的每个元素进行相同的函数处理最终返回一个Iterator。 reduce()
类似栈的思想,先让栈顶的两个元素出栈作为函数的两个参数,再将函数的返回值入栈,然后再让栈顶两个元素出栈,不断循环下去,直到栈里没有元素为止。filter()
的作用是从一个序列中筛选出符合条件的元素。由于filter()
使用了惰性计算,所以只有在取filter()
结果的时候,才会真正筛选并每次返回下一个筛出的元素。sorted()
也是一个高阶函数。用sorted()
排序的关键在于实现一个映射函数。