本篇博文主要介绍一些高级的函数特性,如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
知识星球