python中一切皆可以为对象;而高阶函数的含义为其传入的参数中包含函数对象,接收函数对象为参数的函数为高阶函数。python中有几个内置的高阶函数,包括map(),sorted(),filter();早前的python版本中还有内置的reduce(),现在该函数被放在functools模块中了。
在之前的文章中已经详细讲过了,详情参考https://blog.csdn.net/Always_Go_/article/details/118425093
补充的一点:
对于大部分map()使用的场景,都已经可以用列表推导式简便的替代,对于多个参数传入的情形,一般需要转换为下标的形式:
>>>a=[1,2,3] >>>b=[10,20,30] >>>[a[i]+b[i] for i in range(3)] [11, 22, 33]
提到sorted()函数必须要和sort()函数区分:
sorted()函数是内置函数,接收一个可迭代对象,对所有可迭代对象均可按照一定规则进行排序,会返回一个新的可迭代对象。
sort()函数是List对象的一个方法,直接修改原list,返回None
>>>a=[2,3,1] >>>b=sorted(a)#返回新对象 >>>b [1, 2, 3] >>>a#原对象不改变 [2, 3, 1] >>>a=[2,3,1] >>>b=a.sort()#返回None >>>a [1, 2, 3]#改变原对象 >>>b >>>sort(a)#内置方法只有sorted() Traceback (most recent call last): File "<input>", line 1, in <module> NameError: name 'sort' is not defined
而sorted()函数本身非常有用,尤其和key结合起来。之所以sorted是高阶函数,因为其内部参数可以接收一个函数对象。
>>>a=[1,-2,3,-1,10,-20] >>>sorted(a)#默认从小排到大 [-20, -2, -1, 1, 3, 10] >>>sorted(a,reverse=True)#从大排到小 [10, 3, 1, -1, -2, -20] >>>sorted(a,key=lambda x:x**2)#key传入一个函数对象,通过每个数的平方来排序 [1, -1, -2, 3, 10, -20]
对于多维列表排序:
>>>a=[[2,3,1],[10,-1,3],[-1,20,2]] >>>sorted(a,key=lambda x:x[1])#根据每行第2个数进行排序 [[10, -1, 3], [2, 3, 1], [-1, 20, 2]]
对于字符串排序:
>>>a=['hacca','de','djnhg'] >>>sorted(a,key=lambda x:x[-1]) ['hacca', 'de', 'djnhg']
对于自定义的对象排序:
class A: def __init__(self,a,b): self.a=a self.b=b def __repr__(self): return '%s_%s_%s'%(self.__class__.__name__,self.a,self.b) >>>x=[A(1,2),A(-1,3),A(-10,1)] >>>sorted(x,key=lambda x:x.a) [A_-10_1, A_-1_3, A_1_2]
总之,sorted()函数配合key使用lambda匿名函数非常好用。
filter()顾名思义,为一个过滤函数;接收一个函数和一个可迭代对象,将函数依次作用在该可迭代对象上,其中函数每次必须返回True或者False.最后将返回为True的元素保留下来。
>>>a=[1,2,3,4,5] >>>def func(x): >>> return x%2==0 >>>list(filter(func,a))#a中的2和4传入函数时返回为True,因此最后只剩下2和4 [2, 4] >>>[x for x in [1,2,3,4,5] if x%2==0]#也可以用列表推到式实现 [2, 4]
举一个相对比较复杂的例子。如何认定学生是否偏科呢?符合如下其中一条的学生,将被视为偏科:
有 2 科成绩在 80 分以上,有一科在 60 分以下。
有 1 科成绩在 90 分以上,另外 2 科成绩都在 60 分以下。
有 1 科成绩在 90 分以上,但三科的平均分在 70 分以下。
scores = [ ("Emma", 89 , 90 , 59), ("Edith", 99 , 49 , 59), ("Sophia", 99 , 60 , 20), ("May", 40 , 94 , 59), ("Ashley", 89 , 90 , 59), ("Arny", 89 , 90, 69), ("Lucy", 79 , 90 , 59 ), ("Gloria", 85 , 90 , 59), ("Abby", 89 , 91 , 90)] def handle_filter(a): s = sorted(a[1: ]) #对三科成绩进行排序 #有 2 科成绩在 80 分以上,并且有 1 科在 60 分以下的 if s[-2] > 80 and s[0] < 60 : return True #有 1 科成绩在 90 分以上,另外 2 科成绩都在 60 分以下 if s[-1] > 90 and s[1] < 60 : return True if s[-2] > 80 and sum(s)/len(s) < 60: #有 1 科成绩在 90 分以上, 且 3 科的平均分在 70 分以下 return True return False >>>list(filter(handle_filter, scores)) [('Emma', 89, 90, 59), ('Edith', 99, 49, 59), ('May', 40, 94, 59), ('Ashley', 89, 90, 59), ('Gloria', 85, 90, 59)]
可以看到,对于这样规则比较复杂的过滤,用列表推导式会非常较为麻烦且代码易读性会较差了,这个时候用filter还是更为好看的。但都比for循环要来得好。
python3中reduce都已经在functools模块中,语法为:
reduce(function, sequence[, initial]) -> value
reduce函数接受一个function和一串sequence,并返回单一的值,以如下方式计算: 1.初始,function被调用,并传入sequence的前两个items,计算得到result并返回 2.function继续被调用,并传入上一步中的result,和sequence种下一个item,计算得到result并返回。一直重复这个操作,直到sequence都被遍历完,返回最终结果。 注意. 当initial值被指定时,传入step1中的两个参数分别是initial值和sequence的第一个items。reduce()最多只能接受三个参数,func,sequence,initial。
>>>reduce(lambda a,b:a+b,[1,2,3,4,5])#传入的第一个值为1 >>>reduce(lambda a,b:a+b,[1,2,3,4,5],100)#传入的第一个初始值为100 115
reduce这个功能完全可以用sum来代替了。