Python函数式编程
2017-07-14 11:31
218 查看
把函数作为参数传入,这样的函数称为高阶函数,函数式编程就是指这种高度抽象的编程范式。
map()函数接收两个参数,一个是函数,一个是Iterable,map将传入的函数依次作用到序列的每个元素,并把结果作为新的Iterator返回。
reduce把一个函数作用在一个序列[x1, x2, x3, …]上,这个函数必须接收两个参数,reduce把结果继续和序列的下一个元素做累积计算,其效果就是:
reduce(f, [x1, x2, x3, x4]) = f(f(f(x1, x2), x3), x4)
filter()接收一个函数和一个序列,把传入的函数依次作用于每个元素,然后只保留使函数返回值是False的元素。
sorted()函数是一个高阶函数,它还可以接收一个key函数来实现自定义的排序,key指定的函数将作用于list的每一个元素上,并根据key函数返回的结果进行排序,要进行反向排序,不必改动key函数,可以传入第三个参数reverse=True
高阶函数除了可以接受函数作为参数外,还可以把函数作为结果值返回。
关键字lambda表示匿名函数,冒号前面的x表示函数参数。
匿名函数有个限制,就是只能有一个表达式,不用写return,返回值就是该表达式的结果。
用匿名函数有个好处,因为函数没有名字,不必担心函数名冲突。此外,匿名函数也是一个函数对象,也可以把匿名函数赋值给一个变量,再利用变量来调用该函数
要增强now()函数的功能,比如,在函数调用前后自动打印日志,但又不希望修改now()函数的定义,这种在代码运行期间动态增加功能的方式,称之为“装饰器”(Decorator)
偏函数:functools.partial的作用就是,把一个函数的某些参数给固定住(也就是设置默认值),返回一个新的函数,调用这个新函数会更简单
def add(x,y,f): return f(x)+f(y) print(add(-5,6,abs))
map()函数接收两个参数,一个是函数,一个是Iterable,map将传入的函数依次作用到序列的每个元素,并把结果作为新的Iterator返回。
#map def f(x): return x*x print(list(map(f,range(10)))) #[0, 1, 4, 9, 16, 25, 36, 49, 64, 81] print(list(map(str,range(10)))) #['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']
reduce把一个函数作用在一个序列[x1, x2, x3, …]上,这个函数必须接收两个参数,reduce把结果继续和序列的下一个元素做累积计算,其效果就是:
reduce(f, [x1, x2, x3, x4]) = f(f(f(x1, x2), x3), x4)
#reduce from functools import reduce def add(x,y): return x+y print(reduce(add,range(10))) #45 def fn(x,y): return 10*x+y print(reduce(fn,range(10)))#123456789 #str2int def str2int(s): def fn(x,y): return 10*x+y def char2num(s): return {'0':0,'1':1,'2':2,'3':3,'4':4,'5':5,'6':6,'7':7,'8':8,'9':9}[s] return(reduce(fn,map(char2num,s))) print(str2int('3425556')) #3425556 #将英文单词规范化:首字母大写,其余小写 L1=['adam','LISA','barT'] def stad(s): temp=s[0].upper()+s[1:].lower() return temp L2=list(map(stad,L1)) print(L2) #['Adam', 'Lisa', 'Bart'] #求乘积 def prod(L): def mul(x,y): return x*x return reduce(mul,L3) L3=[3,5,7,9] print('3 * 5 * 7 * 9 =',prod(L3)) #3 * 5 * 7 * 9 = 6561 #将字符串转换为float def str2float(s): def char2num(s): return {'0':0,'1':1,'2':2,'3':3,'4':4,'5':5,'6':6,'7':7,'8':8,'9':9}[s] def findpoint(s): n=0; for c in s: if (c=='.'): break else: n=n+1 return n def fn(x,y):#计算小数点之前的位数 return 10*x+y def gn(x,y):#计算小数点之后的位数 return 0.1*x+y point=findpoint(s) zhen=reduce(fn,map(char2num,list(s[0:point]))) fen=0.1*reduce(gn,map(char2num,list(s[-1:point:-1])))#此处注意要乘以0.1 return zhen+fen print(str2float('123.456')) #123.456 #将字符串转换为float 先计算没有小数点的结果,再根据小数点的位置除以相应的数据 def str2float(s): def char2num(s): return {'0':0,'1':1,'2':2,'3':3,'4':4,'5':5,'6':6,'7':7,'8':8,'9':9}[s] def findpoint(s): n=0; for c in s: if (c=='.'): break else: n=n+1 return n def fn(x,y):#计算小数点之前的位数 return 10*x+y point=findpoint(s) return reduce(fn,map(char2num,list(s[0:point])+list(s[point+1:])))*pow(10,-point)#将两个list相连只需用+即可 print(str2float('123.456')) #123.456
filter()接收一个函数和一个序列,把传入的函数依次作用于每个元素,然后只保留使函数返回值是False的元素。
#filter #filter()函数返回的是一个Iterator,也就是一个惰性序列,所以要强迫filter()完成计算结果,需要用list()函数获得所有结果并返回list。 def is_odd(n): return n%2==1 print(list(filter(is_odd,range(16))))#将所有偶数过滤掉 [1, 3, 5, 7, 9, 11, 13, 15] #删除序列中的空字符串 def not_empty(s): return s and s.strip() #strip函数没有参数时默认删掉字符串中的空字符 print(list(filter(not_empty,['A',' ','B',None,'C',' ']))) #['A', 'B', 'C'] #找出所有的素数 def _odd_iter():#生成器,奇数的无限序列 n=1 while True: n=n+2 yield n def _not_divisible(n):#筛选函数 return lambda x :x%n>0 def primes(): yield 2 it=_odd_iter()# 初始序列 while True: n=next(it)# 返回序列的第一个数 yield n it=filter(_not_divisible(n),it)# 构造新序列 # 打印1000以内的素数: for n in primes(): if n < 1000: print(n) else: break #找出所有回文数 def is_palindrome(n): s=list(str(n)) s2=s[::-1] n=0 for i in range(len(s)): if (s[i]==s2[i]): n=n+1 return n==len(s) def is_palindrome2(n): #将n转化成str,与逆转后的str比较是否相等 return str(n) == str(n)[::-1] output=filter(is_palindrome,range(1,1000)) print(list(output)) output=filter(is_palindrome2,range(1,1000)) print(list(output)) #[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, 202, 2 #12, 222, 232, 242, 252, 262, 272, 282, 292, 303, 313, 323, 333, 343, 353, 363, 373, 383, 393, 404, 414, 424, 434, 444, 4 #54, 464, 474, 484, 494, 505, 515, 525, 535, 545, 555, 565, 575, 585, 595, 606, 616, 626, 636, 646, 656, 666, 676, 686, 6 #96, 707, 717, 727, 737, 747, 757, 767, 777, 787, 797, 808, 818, 828, 838, 848, 858, 868, 878, 888, 898, 909, 919, 929, 9 #39, 949, 959, 969, 979, 989, 999]
sorted()函数是一个高阶函数,它还可以接收一个key函数来实现自定义的排序,key指定的函数将作用于list的每一个元素上,并根据key函数返回的结果进行排序,要进行反向排序,不必改动key函数,可以传入第三个参数reverse=True
#sorted print(sorted([36, 5, -12, 9, -21], key=abs)) #[5, 9, -12, -21, 36] print(sorted(['bob', 'about', 'Zoo', 'Credit'])) #['Credit', 'Zoo', 'about', 'bob'] print(sorted(['bob', 'about', 'Zoo', 'Credit'], key=str.lower)) #['about', 'bob', 'Credit', 'Zoo'] #按照姓名排序 L = [('Bob', 75), ('Adam', 92), ('Bart', 66), ('Lisa', 88)] def by_name(t): return t[0] L2=sorted(L,key=by_name) print(L,'\n',L2)#[('Bob', 75), ('Adam', 92), ('Bart', 66), ('Lisa', 88)] [('Adam', 92), ('Bart', 66), ('Bob', 75), ('Lisa', 88)] #按照成绩排序 def by_score(t): return t[1] L3=sorted(L,key=by_score,reverse=True) #[('Adam', 92), ('Lisa', 88), ('Bob', 75), ('Bart', 66)] print(L,'\n',L3) L4=sorted(L,key=by_score) # [('Bart', 66), ('Bob', 75), ('Lisa', 88), ('Adam', 92)] print(L,'\n',L4)
高阶函数除了可以接受函数作为参数外,还可以把函数作为结果值返回。
#返回函数 def count(): fs=[] for i in range(1,4): def f(): return i*i fs.append(f) #此处虽然i在每次循环的值都不同,但是因为没有立刻执行函数,所以i的值没有固定,会随着循环而每次都不同 return fs f1,f2,f3=count() print(f1(),f2(),f3())#此时调用函数count,执行f函数,i=3,结果均为9 def count2(): def f(i): def g(): return i*i return g fs=[] for i in range(1,4): fs.append(f(i))#立刻用不同的i调用函数f,返回值不同 return fs f1,f2,f3=count2() print(f1(),f2(),f3()) #1 4 9
关键字lambda表示匿名函数,冒号前面的x表示函数参数。
匿名函数有个限制,就是只能有一个表达式,不用写return,返回值就是该表达式的结果。
用匿名函数有个好处,因为函数没有名字,不必担心函数名冲突。此外,匿名函数也是一个函数对象,也可以把匿名函数赋值给一个变量,再利用变量来调用该函数
#匿名函数 def build(*args): def f(): sum=0 for i in args: sum=sum+i*i return sum return f def build2(x,y): return lambda:x*x+y*y f1=build(2,3) f2=build2(2,3) print(f1(),f2()) #13 13 #使用lambda,x 从 0 迭代到 4 的时候每次都会先赋值给 n;所以 返回的"闭包"中参数n 是绑定的,不会因为 x 的变化而变化 squares = [] for x in range(5): squares.append(lambda n=x: n*2) print(squares[2]()) #使用之前的返回函数,达到与上述相同的目的 squares2 = [] def f(x): def g(): return x*2 return g for x in range(5): squares2.append(f(x)) print(squares2[2]()) """以下三种结果相同""" def build(x, y): return lambda: x * x + y * y x = build(3, 6) print(x()) def build(): return lambda x, y: x * x + y * y y = build() print(y(3, 6)) z = lambda x, y: x * x + y * y print(z(3, 6))
要增强now()函数的功能,比如,在函数调用前后自动打印日志,但又不希望修改now()函数的定义,这种在代码运行期间动态增加功能的方式,称之为“装饰器”(Decorator)
#装饰器Decorator import functools def now(): print('2017-7-14') def log(func): @functools.wraps(func) def wrapper(*args,**kw): print('call %s():' % func.__name__)#打印日志 return func(*args,**kw)#调用函数 return wrapper def log2(text): def decorator(func): @functools.wraps(func) def wrapper(*args, **kw): print('%s %s():' % (text, func.__name__)) return func(*args, **kw) return wrapper return decorator @log#相当于执行now = log(now),now变量指向了新的函数,调用时会在log()中返回wrapper()函数 def now(): print('2017-7-14') print(now.__name__) #now print(now()) #call_now() 2017-7-14 @log2('execute')# now = log('execute')(now),首先执行log('execute'),返回的是decorator函数,再调用返回的函数,参数是now函数,返回值最终是wrapper函数 def now2(): print('10:21') print(now2.__name__) #now2 print(now2()) #execute now2(): 10:21 #用一个@log的decorator,使它既支持带参数,也支持不带参数 def log(text): def real_decorator(func): @functools.wraps(func) def wrapper(*args, **kw): if isinstance(text,str): display=text else:display='' print('begin call',display) func() print('end call') return wrapper if isinstance(text,str): return real_decorator else: return real_decorator(text) @log('ext') def f(): print('call f()') #begin call ext call f() end call @log def f1(): print('call f1()') print(f(),'\n',f1()) #begin call call f1() end call
偏函数:functools.partial的作用就是,把一个函数的某些参数给固定住(也就是设置默认值),返回一个新的函数,调用这个新函数会更简单
#偏函数 print(int('1243')) print(int('1243',base=6)) #315 将6进制的‘1243’转化成十进制的int def int6(x,base=6): return int(x,base) print(int6('1243')) #315 def int2(x, base=2):#另外定义一个有默认参数的函数,省的每次都设置base的值 return int(x, base) #此处不用return int(x, base=2)是为了代码灵活性,调用int2时也可以传入其他参数 print(int2('10001010')) #138 print(int2('10001010',6))#280158 调用int2时也可以传入其他参数 import functools int2=functools.partial(int,base=2)#定义偏函数 print(int2('10001010')) #138 #但也可以在函数调用时传入其他值桶上面自己定义的int2 #偏函数的参数包括函数对象,*args和**kw三个,默认情况下kw = { 'base': 2 } print(int2('1000000', base=10)) #1000000
相关文章推荐
- 体验Python函数式编程
- Python函数式编程指南(三):迭代器
- Python函数式编程指南(四):生成器
- Python函数式编程指南(四):生成器
- Python函数式编程指南(一):函数式编程概述
- 【Python环境】如何使用正确的姿势进行高效Python函数式编程?
- Python函数式编程指南
- python函数式编程
- Python函数式编程指南(一):概述
- python函数式编程之高阶函数学习
- 15.python函数式编程(二)—返回函数,匿名函数
- Python函数式编程指南(一):概述
- Python函数式编程指南(四):生成器(转载)
- Python函数式编程指南(二):函数
- Python函数式编程
- Python函数式编程指南(一):函数式编程概述
- python函数式编程
- 研究两天python函数式编程的总结和心得
- python函数式编程
- python函数式编程