函数式编程:
概念:是一种抽象程度很高的编程方式,允许将一个函数作为参数传入另一个函数,还允许返回一个函数。
接下来介绍:
map/reduce,filter,stored函数,返回函数,匿名函数,装饰器,偏函数
map函数:
问题:如果我想对一个列表[1,2,3,4,5,6,7,8,9]中的每一个元素求其平方:
L = [1,2,3,4,5,6,7,8,9]deff(L):
l=[]for i inL:
l.append(i*i)return l
我们需要编写一个函数,然后作用在这个列表L上,有没有更简洁的写法呢?是有的,可以用map函数
L = [1,2,3,4,5,6,7,8,9]deff(x):return x*x
l= map(f,L)
print(list(l))
map()函数接收两个参数:第一个是函数名,第二个是Iterable,并将结果作为Iterator返回。(Iterable,Iterator的概念,请参考https://www.cnblogs.com/double-lin/p/9757953.html)
reduce函数
reduce是将函数f作用在序列[x1,x2,x3...]上,并且函数f接收两个参数:
reduce(f,[x1,x2,x3,x4]) = f(f(f(x1,x2),x3),x4)
from functools importreducedeffn(x,y):return 10*x +y
reduce(fn,[1,2,3])
练习一:利用map()函数,把用户输入的不规范的英文名字,变为首字母为大写,其他小写的规范名字。输入:['adam','LISA','barT'],输出:['Adam','Lisa','Bart']。
#/usr/bin!
'''首先,定义一个函数能够将字符串转变为,首字母大写其余小写;然后再将map函数作用在这个包含字符串的list集合上'''
deftoUpperLower(s):#字符串长度
m =len(s)
first=s[0].upper()
end= s[1:m].lower()return (first+end)print(list(map(toUpperLower,['adam','LISA','barT'])))
练习二:Python提供的sum()函数可以接受一个list并求和,请编写一个prod()函数,可以接受一个list并利用reduce()求积:
#/usr/bin!
from funtools importreducedefprod(L):deffn(x,y):
retrun(x*y)return reduce(fn,L)
练习三:利用map()和reduce()编写一个str2float()函数,把字符串'123.456'转换为浮点型123.456
from functools importreduce
DIGITS= {'0': 0, '1': 1, '2': 2, '3': 3, '4': 4, '5': 5, '6': 6, '7': 7, '8': 8, '9': 9}defchar2num(s):returnDIGITS[s]defstrToFloat(s):
s= s.split('.')if s[0]=='':
first= 0.0
else:
first= reduce(lambda x,y: x*10 +y,map(char2num,s[0]))
l= list(reversed(s[1]))
l.append('0')
end= reduce(lambda x,y: x*(1e-1) +y,map(char2num,l))return (first+end)print(strToFloat('.213'))
filter函数
python的内置函数filter函数和map函数类似,接收两个参数:函数和序列,和map()不同的是,filter()把函数以此作用在列表元素上,然后根据返回值是True还是False,来决定是否保留。
练习四:回数是从左往右数和从右往左数都是一样的数,利用filter()函数,来筛选出来回数:
defis_palindrome(num):
s=str(num)if len(s)==1:returnint(s)elif len(s)%2 ==0:for i in range(0,len(s)//2):if s[i] != s[len(s)-i-1]:return
returnint(s)else:for j in range(0,len(s)//2):if s[j] != s[len(s)-j-1]:return
returnint(s)
output= filter(is_palindrome, range(1, 1000))print('1~1000:', list(output))if list(filter(is_palindrome, range(1, 200))) == [1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 22, 33, 44, 55, 66, 77, 88, 99, 101, 111, 121, 131, 141, 151, 161, 171, 181, 191]:print('测试成功!')else:print('测试失败!')
sorted函数
排序:sorted()也是一个高阶函数,可以用key=接收自定义的函数,和reverse=True或者False(默认False)逆序
练习五:假设我们用一组tuple来表示学生的名字和成绩:L = [('Bob', 75), ('Adam', 92), ('Bart', 66), ('Lisa', 88)],请用sorted()函数对列表L分别按名字和成绩排序:
L = [('Bob', 75), ('Adam', 92), ('Bart', 66), ('Lisa', 88)]
defby_name(t):returnt[0]defby_score(t):return t[1]
sorted(L,key=by_name)
sorted(L,key=by_score)
匿名函数:
通过使用lambda关键字,来定义一个简单的函数,lambda x: x*x
冒号前的变量x是参数,返回结果x*x,冒号后,只能有一个表达式
练习六: 请用匿名函数改造下列代码:
defis_odd(n):return n % 2 == 1L= list(filter(is_odd,range(1,20)))#使用匿名函数
L = list(filter(lambda n: n%2==1,range(1,20)))
返回函数:
函数作为结果值,返回。
练习七:利用闭包返回一个计数器函数,每次调用它返回一个递增整数:
参考:https://www.cnblogs.com/cccmon/p/7930550.html
s = 0 #设置全局变量
defcreateCounter():defcounter():global s #引用全局变量
s = s+1
returnsreturncounter
counterA=createCounter()print(counterA()) #每次调用子函数,都是会保留上次s的值进行计算的
defcreateCounter():
s=[0]defcounter():
s[0]= s[0]+1
returns[0]return counter
装饰器:
在动态执行函数的时候,我们希望在不改变原来函数代码的下,动态增强该函数的功能,如在调用的时候打印一下该函数的开始执行提示。
练习八:写一个装饰器log,使其即满足:
@log
def f():
pass
又满足:
@log('execute')
def f():
pass
importfunctoolsdeflog(param):ifcallable(param):def wrapper(*args, **kw):print('%s function()' % (param.__name__))
param(*args, **kw)returnwrapperdefdecorator(func):
@functools.wraps(func)def wrapper(*args, **kw):print('%s %s():' % (param, func.__name__))return func(*args, **kw)returnwrapperreturn decorator
偏函数:
就是使调用函数的时候更简单一点:
importfunctools
int2= functools.partial(int, base=2)
int2('1000000')
#输出: 64