python中高阶函数的定义为:接收函数作为参数,或者把函数作为结果返回的函数就是高阶函数(higher-order function)
在函数式编程范式中,最常见的高阶函数有map、filter、reduce和sorted。
下面着重使用python自定义函数来实现他们的功能,这样更有助于加深理解和记忆
首先先来介绍个小技巧,在jupyer notebook中,如果遇到我们想调用的函数,却又不知道如何传参,以及想知道这个函数更多的细节时,我们可以sorted?来查看这个函数的帮助文档。
如果想知道更全的知识点,可以查看Python官方文档。
Signature: sorted(iterable, /, *, key=None, reverse=False)
Docstring:
Return a new list containing all items from the iterable in ascending order.
A custom key function can be supplied to customize the sort order, and the
reverse flag can be set to request the result in descending order.
Type: builtin_function_or_method
我们很清楚的看到,他可以接受一个可迭代对象,然后有两个可选的默认仅限关键字参数Key和reverse,返回值为一个新的list
下面我们来用python的自定义函数来实现soreted的功能实现
def sorted1(iterable,reverse = True ,key = None):
newlist = []
for i in iterable:
# 这里的key和下面的key的作用是相同的,并不会修改原值
ci = i if key is None else key(i)
for j, k in enumerate(newlist):
# key用来定义排序顺序,并不会修改原值
ck = k if key is None else key(k)
# 下面这两行用来控制reverse的参数,来控制排序是按升序还是降序
control = ci > ck if reverse == True else ci < ck
if control:
newlist.insert(j,i)
break # 找到合适的位置
else:
newlist.append(i)
return newlist
sorted1([1,2,3,4,5],reverse=True,key = lambda x : 100 - int(x))
[5, 4, 3, 2, 1]
上面这个函数实现了和sorted一样的功能。
key实际上传入的是一个函数对象,然后分别作用在原序列的元素上,返回值用来比较,这也是sorted排序的关键地方
reverse用来控制升序还是降序
下面来普及个冷知识,其实字符串之间也是可以比较大小的。
Strings (instances of str) compare lexicographically using the numerical Unicode code points (the result of the built-in function ord()) of their characters.
String 通过内置函数ord()获得每个字符的unicode编码进行比较大小。先比较两个对象的第0个元素,大小关系即为对象的大小关系,如果相等,则继续比较后续元素,先终止迭代的认为是小的
In [1]: "ac" > "abb" > "ab"
Out[1]: True
这里用的是链式比较,等价于
In [2]: "ac" > "abb" and "abb" > "ab"
Out[2]: True
Init signature: map(self, /, *args, **kwargs)
Docstring:
map(func, *iterables) --> map object
Make an iterator that computes the function using arguments from
each of the iterables. Stops when the shortest iterable is exhausted.
Type: type
Subclasses:
接收两个参数,function和可迭代对象,可以同时多个可迭代对象
返回值为一个类似generator的迭代器
def map1(function,*iterable):
for args in zip(*iterable):
yield function(*element)
list(map1(lambda x :x+1 ,[1,2,3]))
[2, 3, 4]
map将传入的函数依次作用于序列的每个元素,并把结果作为新的iterable返回
Init signature: filter(self, /, *args, **kwargs)
Docstring:
filter(function or None, iterable) --> filter object
Return an iterator yielding those items of iterable for which function(item)
is true. If function is None, return the items that are true.
Type: type
Subclasses:
这次我们先用python自定义函数来实现filter
的功能
def filter1(function,iterable):
for i in iterable:
if function is None:
if i:
yield i
else:
if function(i):
yield i
g = filter1(None, [0,1,2,3])
for i in g:
print(i)
1
2
3
filter接收两个参数,function和iterable, 他会把传入的函数依次作用于每个元素,然后根据返回值是True或者False来决定是保留还是丢弃元素。
如果function是None,就返回bool值为真的元素
Docstring:
reduce(function, sequence[, initial]) -> value
Apply a function of two arguments cumulatively to the items of a sequence,
from left to right, so as to reduce the sequence to a single value.
For example, reduce(lambda x, y: x+y, [1, 2, 3, 4, 5]) calculates
((((1+2)+3)+4)+5). If initial is present, it is placed before the items
of the sequence in the calculation, and serves as a default when the
sequence is empty.
Type: builtin_function_or_method
reduce从functools模块中导入
很明显可以看到,reduce接收三个参数,其中一个为可选参数,返回值为单一的值(single value)
照例还是先用python自定义函数来实现reduce功能
def reduce1(function,sequence,initial = None):
it = iter(sequence) # def 函数实现的关键在于将传入的可迭代sequence转换成iterator迭代器
if initial is None:
value = next(it) # 因为it现在是一个迭代器,而这里的value恰当的当的迭代器的第一个元素赋值给了value,呼应了下面的for循环遍历
else:
value = initial
for element in it: # 这里如果it不是迭代器,我们可以直接[1:]开始迭代好像也可以
value = function(value,element)
return value
reduce1(lambda x,y : x*y, [1, 2, 3, 4], 3)
72
function为函数对象,这个函数必须接收两个参数
sequence为一个序列,函数作用在这个序列上,reduce把结果继续和序列的下一个元素做累计计算,起效果相当于
reduce(f, [x1, x2, x3, x4]) = f(f(f(x1, x2), x3), x4)
initial为初始值,可选参数
函数式语言通常会提供map、filter和reduce的三个高阶函数,filter和map还是内置函数,在python3中,由于引入了列表推导式和生成器表达式,他们变得不那么重要了,列表推导和生成器具有map和filter的功能,而且更易于阅读。
In [3]: def func(n):
...: return n * 2
In [6]: list(map(func,range(5)))
Out[6]: [0, 2, 4, 6, 8]
In [5]: [func(n) for n in range(5)]
Out[5]: [0, 2, 4, 6, 8]
In [7]: list(map(func,filter(lambda x : x % 2, range(6))))
Out[7]: [2, 6, 10]
In [9]: [func(n) for n in range(6) if n % 2]
Out[9]: [2, 6, 10]
在python3中,map和filter返回一种迭代器,因此他们的替代品就是生成器表达式
在python2中,reduce是内置函数,但是在python3中放到functools模块中了,这个函数最常用于求和,自从python2.3开始,最好使用内置的sum函数,在可读性和性能方便,这是一项重大改善
In [10]: from functools import reduce
In [11]: from operator import add
In [12]: reduce(add,range(100))
Out[12]: 4950
In [13]: sum(range(100))
Out[13]: 4950
sum和reduce的通用思想是把某个操作连续运用在序列的元素上,累计之前的结果,把一系列的值规约成一个值。
any和all也是内置的归约函数。
all(iterable)
如果iterable的每个元素都为真值,则返回True, all([ ])返回True
any(iterable)
如果iterable中有元素是真值,就返回True,any([ ])返回False