参考教程:廖雪峰官网https://www.liaoxuefeng.com/wiki/0014316089557264a6b348958f449949df42a6d3a2e542c000
函数式编程
一、高阶函数
所谓高阶函数就是函数可以以另外一个函数作为参数。
首先需要了解在Python中变量是可以指向函数的,如下例子:
>>> abs(-5) 5 >>> f=abs >>> f <built-in function abs> >>> abs <built-in function abs> >>> f(-5) 5
可以看到当变量f指向函数名abs后,f也成为了一个求绝对值的函数名,并且可以通过f调用。
函数名的本质也是变量,只是在Python中直接设置了该变量就指向函数。
>>> abs=‘abc‘ >>> abs ‘abc‘ >>> abs(-1) Traceback (most recent call last): File "<pyshell#7>", line 1, in <module> abs(-1) TypeError: ‘str‘ object is not callable
上例中把内置函数名abs指向了一个字符串,那它的本质就变化了,无法再调用其计算绝对值的方法了。(只有在下一次启动Python运行环境后才重置)。
看一个最简单的高阶函数(即以函数名作为参数):
>>> def funa(a): return a*a >>> def funb(a,b,f): return f(a)+f(b) >>> funb(3,4,funa) 25
>>> funb(-6,-10,abs)
16
(一)map/reduce
1、map
map函数接受两个参数,一个是函数,一个是Iterable(可迭代对象)。map将传入的函数依次作用到序列的每个元素,并把结果作为一个新的Iterator(迭代器)返回。
例如,用Python实现一个函数f(x)=x^2,作用到一个列表上。
>>> def fx(n): return n**2 >>> map(fx,[1,2,3,4,5,6,7,8,9]) <map object at 0x0000000002DA8D30>
注意这里结果是一个map对象,实质上是一个迭代器(Iterator),从前面章节了解到迭代器都是惰性的,要把结果转为Iterable来输出。
>>> list(map(fx,[1,2,3,4,5,6,7,8,9])) [1, 4, 9, 16, 25, 36, 49, 64, 81] >>> from collections import Iterator >>> x=map(fx,[1,2,3,4,5,6,7,8,9]) >>> isinstance(x,Iterator) True
虽然通过其他的方法也可以实现上述生成一个结果列表的效果,但map作为一个高阶函数,过程中把运算规则抽象化处理,在应用中可以处理更复杂的函数,比如下例把一个list所有数字转为字符串只需要一行代码:
>>> list(map(str,[1,2,3,4,5])) [‘1‘, ‘2‘, ‘3‘, ‘4‘, ‘5‘]
2、reduce
reduce同样把一个函数作用在一个序列上,但其内部的过程却和map不同,reduce是把函数的结果继续和序列的下一个元素继续计算,同时这个函数必须接受两个参数,所以效果就是:
reduce(f,[a,b,c,d])=f(f(f(a,b)+c)+d)
一个简单的求和示例:
>>> from functools import reduce >>> def myadd(a,b): return a+b >>> reduce(myadd,list(range(1,101))) 5050
另外一个示例,把一个数字序列变成一个数:
>>> def myadd(a,b): return a*10+b >>> reduce(myadd,[1,3,7,9]) 1379
配合使用map和reduce可以把一个数字字符串转换为数值:
>>> def funa(nstr): return int(nstr) >>> reduce(myadd,map(funa,‘12345‘)) 12345
练习:
‘‘‘ 利用map()函数,把用户输入的不规范的英文名字,变为首字母大写,其他小写的规范名字。 输入:[‘adam‘, ‘LISA‘, ‘barT‘],输出:[‘Adam‘, ‘Lisa‘, ‘Bart‘] ‘‘‘ def fun1(stra): return stra.capitalize() name_list=[‘adam‘, ‘LISA‘, ‘barT‘] print(list(map(fun1,name_list)))
‘‘‘ Python提供的sum()函数可以接受一个list并求和, 请编写一个prod()函数,可以接受一个list并利用reduce()求积: ‘‘‘ def fun2(a,b): return a*b def prod(lista): return reduce(fun2,lista) print(‘3 * 5 * 7 * 9 =‘, prod([3, 5, 7, 9])) if prod([3, 5, 7, 9]) == 945: print(‘测试成功!‘) else: print(‘测试失败!‘)
from functools import reduce ‘‘‘ 利用map和reduce编写一个str2float函数,把字符串‘123.456‘转换成浮点数123.456 ‘‘‘ #思路:先把原始字符串分成两部分:整数和小数部分分别处理 #处理整数部分的转换 #1、先把字符转换成数值 def strTonumbera(char): mydic={‘0‘:0,‘1‘:1,‘2‘:2,‘3‘:3,‘4‘:4,‘5‘:5,‘5‘:5,‘6‘:6,‘7‘:7,‘8‘:8,‘9‘:9} return mydic[char] #2、定义整数部分reduce的函数参数 def myfunca(a,b): return a*10+b #3、通过reduce/map将整数字符串转换为整数数值 def funca(strx): return reduce(myfunca,list(map(strTonumbera,list(strx)))) #处理小数部分的转换 #1、定义小数部分reduce的函数参数 def myfuncb(a,b): return a/10+b #2、通过reduce/map将整数字符串转换为整数数值 def funcb(strx): #小数部分的处理与整数相比有个难点就是reduce推算中的处理,这里可以先把序列倒序 stry=list(strx) stry.reverse() print(stry) x=reduce(myfuncb,list(map(strTonumbera,stry))) #这时候还不是最终得数,需要再除以10 return x/10 def str2float(strx): #整数部分 X=funca(strx.split(‘.‘)[0]) #小数部分 Y=funcb(strx.split(‘.‘)[1]) return X+Y print(str2float(‘123.589‘)) print(‘str2float(\‘123.456\‘) =‘, str2float(‘123.456‘)) if abs(str2float(‘123.456‘) - 123.456) < 0.00001: print(‘测试成功!‘) else: print(‘测试失败!‘)