函数式编程:
概念:是一种抽象程度很高的编程方式,允许将一个函数作为参数传入另一个函数,还允许返回一个函数。
接下来介绍:
map/reduce,filter,stored函数,返回函数,匿名函数,装饰器,偏函数
map函数:
问题:如果我想对一个列表[1,2,3,4,5,6,7,8,9]中的每一个元素求其平方:
L = [1,2,3,4,5,6,7,8,9] def f(L): l = [] for i in L: l.append(i*i) return l
我们需要编写一个函数,然后作用在这个列表L上,有没有更简洁的写法呢?是有的,可以用map函数
L = [1,2,3,4,5,6,7,8,9] def f(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 import reduce def fn(x,y): return 10*x +y reduce(fn,[1,2,3])
练习一:利用map()函数,把用户输入的不规范的英文名字,变为首字母为大写,其他小写的规范名字。输入:['adam','LISA','barT'],输出:['Adam','Lisa','Bart']。
#/usr/bin! ''' 首先,定义一个函数能够将字符串转变为,首字母大写其余小写;然后再将map函数作用在这个包含字符串的list集合上 ''' def toUpperLower(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 import reduce def prod(L): def fn(x,y): retrun(x*y) return reduce(fn,L)
练习三:利用map()和reduce()编写一个str2float()函数,把字符串'123.456'转换为浮点型123.456
from functools import reduce DIGITS = {'0': 0, '1': 1, '2': 2, '3': 3, '4': 4, '5': 5, '6': 6, '7': 7, '8': 8, '9': 9} def char2num(s): return DIGITS[s] def strToFloat(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()函数,来筛选出来回数:
def is_palindrome(num): s = str(num) if len(s)==1: return int(s) elif len(s)%2 == 0: for i in range(0,len(s)//2): if s[i] != s[len(s)-i-1]: return return int(s) else: for j in range(0,len(s)//2): if s[j] != s[len(s)-j-1]: return return int(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)] def by_name(t): return t[0] def by_score(t): return t[1] sorted(L,key=by_name) sorted(L,key=by_score)
匿名函数:
通过使用lambda关键字,来定义一个简单的函数,lambda x: x*x
冒号前的变量x是参数,返回结果x*x,冒号后,只能有一个表达式
练习六: 请用匿名函数改造下列代码:
def is_odd(n): return n % 2 == 1 L = 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 #设置全局变量 def createCounter(): def counter(): global s #引用全局变量 s = s+1 return s return counter counterA = createCounter() print(counterA()) #每次调用子函数,都是会保留上次s的值进行计算的
def createCounter(): s = [0] def counter(): s[0] = s[0]+1 return s[0] return counter
装饰器:
在动态执行函数的时候,我们希望在不改变原来函数代码的下,动态增强该函数的功能,如在调用的时候打印一下该函数的开始执行提示。
练习八:写一个装饰器log,使其即满足:
@log
def f():
pass
又满足:
@log('execute')
def f():
pass
import functools def log(param): if callable(param): def wrapper(*args, **kw): print('%s function()' % (param.__name__)) param(*args, **kw) return wrapper def decorator(func): @functools.wraps(func) def wrapper(*args, **kw): print('%s %s():' % (param, func.__name__)) return func(*args, **kw) return wrapper return decorator
偏函数:
就是使调用函数的时候更简单一点:
import functools int2 = functools.partial(int, base=2) int2('1000000')
#输出: 64