本篇博文主要介绍一些高级的函数特性,如map,reduce,filter,sort,装饰器,lambda等
 
1. map 这个map是指map/reduce中的map,而不是类似jdk的map数据结构
在python中,map接收两个参数,第一个为函数,第二个为一个可迭代的对象,作用是顺序的将迭代器中的元素丢给函数执行,并将结果作为新的Iterator返回
如将列表中的每个数求平方
1 2 3 4 5 6 7 8 9 10 >>> [ x*x for  x in  range(1,6)] [1, 4, 9, 16, 25] >>> def f(x): ...   return  x * x ...  >>> list(map(f, range(1,6))) [1, 4, 9, 16, 25] 
 
上面这样对比之后,发现列表生成式的写法更加简洁,并不能凸显map的优越性
换一个例子,将奇数采用*2,偶数采用平方的方式,则用列表生成式不太好写了
1 2 3 4 5 6 7 8 >>> def f(x): ...   if (x % 2==0) : ...     return  x * x ...   else : ...     return  x *2  ...  >>> list(map(f, range(1,6))) [2, 4, 6, 16, 10] 
 
2. reduce map相当于是顺序的执行迭代器中的元素;而reduce则是每个元素执行完毕之后,会与下一个元素一起进行计算,最终返回的是函数最终的计算结果
一个典型的case如,获取列表中元素的和
1 2 3 4 5 6 7 >>> from functools import reduce >>> def f(x, y): ...   return  x + y ...  >>> reduce(f, range(1, 100)) 4950 
 
需要额外注意的是使用reduce需要引入对应的包 
3. filter 过滤,同样接收两个参数,第一个为过滤函数(返回True/False,True表示保留);第二个为可迭代的对象
如过滤数组中的所有偶数,只保留奇数
1 2 3 4 5 >>> def f(s): ...   return  s % 2 == 1 ...  >>> list(filter(f, range(1, 10))) [1, 3, 5, 7, 9] 
 
4. sorted sorted函数可以实现针对列表的排序,也可以接收一个key函数来实现自定义的排序,如按照绝对值大小进行排序
1 2 3 >>> l=[36, 5, -12, 9, -21] >>> sorted(l, key=abs) [5, 9, -12, -21, 36] 
 
5. 匿名函数 lambda 使用lambda来修饰匿名函数,一般就是一个表达式,配合map/reduce等函数使用时,可能会非常简洁
语法 
lambda 参数: 执行逻辑
如针对列表中,每个数求平方后得出新的列表
1 2 >>> list(map(lambda x: x*x, range(1, 5))) [1, 4, 9, 16] 
 
将前面的求和进行改造
1 2 >>> reduce(lambda x,y:x+y, range(1, 100)) 4950 
 
6. 装饰器 在python中这个装饰器的概念更加类似java中的代理模式,可以增强函数的某些操作,在实际使用中,和我们通常说的切面比较像
因为在python中函数可以作为变量来传参使用,因此装饰器模式的实质就是包装一下需要执行的方法,然后在这个方法执行前后做一些事情
实例1: 
通过装饰器模式来统计方法的执行耗时
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 import  functoolsimport  timeprint('----------------------- time start -----------------' ) def  metric (func) :    @functools.wraps(func)     def  wrapper (*args, **kw) :         start = time.time()         try :             return  func(*args, **kw)         finally :             end = time.time()             print('%s() execute cost: %f() s'  % (func.__name__, (end - start)))     return  wrapper @metric def  timeCal () :    try :         print('time cal now!' )         time.sleep(1 )     except  InterruptedError as  e:         print(e)     return  'hello world'  print('res' , timeCal()) try :    time.sleep(2 ) except  InterruptedError as  e:    print(e) print('----------------------- time over -----------------' ) 
 
看下上面的metric方法,就是具体的装饰器实现方式,在需要引用的函数上面加上 @metric 即可了;需要额外注意的是在metric函数内部的wrapper函数上,多加了一行`@functools.wraps (func),主要是针对直接使用metric(timeCall)的调用方式时,返回的函数的签名依然为timeCall`,具体相关逻辑,参考: python教程之装饰器 
上面执行结果的输出如下
1 2 3 4 5 ----------------------- time start ----------------- time cal now! timeCal() execute cost: 1.004160() ms res hello world ----------------------- time over ----------------- 
 
实例2: 
打印函数执行的日志(如常见的提供rpc服务,输出函数执行时的请求参数和返回结果), 我们现在考虑这个装饰器可以自主选择是否传参的case
看下面装饰器的具体实现中,首先是判断logger参数,如果是函数方式,则表示注解上没有额外参数,因此返回的是 decorate(prefix);否则返回decorate,两者之间的区别就是一个传参层级的问题 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 print('----------------------- logger start -----------------' ) def  logger (prefix) :    def  decorate (func) :         @functools.wraps(func)         def  wrapper (*args, **kw) :             if  not  hasattr(prefix, '__call__' ):                 print("prefix %s() req %s(), %s(): "  % (prefix, args, kw))             else :                 print("method %s() req %s(), %s(): "  % (func.__name__, args, kw))             return  func(*args, **kw)         return  wrapper          if  hasattr(prefix, '__call__' ):         return  decorate(prefix)     else :         return  decorate @logger('selfCal') def  selfCal () :    print('cal1....' ) @logger def  selfCal2 (text) :    print('cal2....' , text) selfCal() selfCal2("2222" ) print('----------------------- logger end -----------------' ) 
 
II. 其他 一灰灰的个人博客,记录所有学习和工作中的博文,欢迎大家前去逛逛
2. 声明 尽信书则不如,已上内容,纯属一家之言,因个人能力有限,难免有疏漏和错误之处,如发现bug或者有更好的建议,欢迎批评指正,不吝感激
3. 扫描关注 一灰灰blog 
知识星球