2020.7.2 装饰器 偏函数
装饰器Decorator
含义:在代码运行期间动态增加功能的方式
实质:返回函数的高阶函数(即参数中含有函数,且返回一个函数)
用法:要用函数前用Python的 @ 语法标注Decorator
例一:
一个打印日志的Decorator
定义:
def log(func): def wrapper(*args,**kw): #1 print('call %s()'%func.__name__) #每个函数都有一个__name__属性,表示函数名 return func(*args,**kw) #2 return wrapper
这就是定义一个Decorator的基本格式
即:
def log(func): def wrapper(*args,**kw): #1 #操作 return func(*args,**kw) #2 return wrapper
#2处不能删去,表示Decorator运行后要执行将要执行的函数,没有这句话,就会只执行log,而不执行后续函数
运行:
@log #1 def now(): print('2020.7.2') now()
#1处log在now()前,表示 log是函数now()的Decorator,在执行now()前会先运行log
结果:
call now()
2020.7.2
如果不要#2,即wrapper中的return func(*args , **kw)时,结果:
call now()
只运行了log,而没有运行函数now
说明:Decorator是和后续引用的函数捆绑的,必须在Decorator中显式表明执行了后续函数,即#2
def wrapper(*args , **kw) #操作 return func(*args,**kw)
把@log放在now()前,相当于执行了语句
now=log(now)
由于函数名是变量,所以@log后的now函数,调用后不再是之前的now函数了,而是log中返回的那个函数,即wrapper,这也可以解释为什么没有#2就无法执行原来now()中的语句了
三层嵌套装饰器Decorator:装饰器本身需要传入参数,类似 @log('execute') 这样
方法:再加一层返回Decorator的高阶函数
def log( text ): def decorator(func): def wrapper(*args , **kw): print('%s call%s()'%(text,func.__name__)) return func(*args , **kw) return wrapper return decorator
用法:
@log( 'execute' ) def num(): print ('2020.7.2')
结果:
execute call num()
2020.7.2
相当于:
now=log( ' execute' )(num)
这样之后,now不代表原来的now()函数,而是wrapper函数了,可以用now.__name__查看
now.__name__ 'wrapper'
通常不希望函数名的变化,这样的话可以避免一些依赖函数签名的代码出错
方法:Python内置的functools.wraps可以保证函数名在decorator前后不变
用法:在内部的wrapper函数前加一句@functools.wraps(func),这个参数func是Decorator后的函数名,使用前需要先import functools
def log(func): @functools.wraps(func) def wrapper(*args,**kw): #…… return func(*args,**kw) return wrapper
三层嵌套的Decorator,仍然是在wrapper前加这句话
def log(text): def decorator(func): @functools.wraps(func) def wrapper(*args,**kw): #…… return func(*args,**kw) return wrapper return decorator
这时再用name查看,则会发现name在使用Decorator前后没有改变
now.__name__ 'now'
例二:一个既支持@log(),又支持@log(text)的Decorator的实现
方法:使用默认参数text=None
def log(text=None): def decorator(func): @functools.wraps(func) def wrapper(*args, **kw): if text: #1 print("%s call %s()" % (text, func.__name__)) else: print("call %s()" % func.__name__) return func(*args, **kw) return wrapper return decorator
把if判断语句用在wrapper下,如#1处
偏函数
含义:通过functools.partial根据某个已存在的函数,通过固定该函数的某个参数,创建一个新函数
举例:由int()得到2进制int2()函数,该函数的作用是将 字符串形式的二进制整数化为十进制整数
import functools int2=functools.partial( int , base = 2 ) int2('10000') 16
如果输入的字符串不是二进制,如 ' 1234 ',在用int2时就会出错
补充:partial可接收三个参数,1、基函数 2、*args 3、**kw
其中
1、基函数:是基于该函数创建的偏函数
2、*args:多出来一部分数字参与运算
3、**kw:需要固定的基函数的参数,格式为 xxx=x
所以,int2('10000')等价于
kw={'base' : 2}
int('10000',**kw)
另有一个关于*args的例子:
max2=functools.partial(max,10)
表示max2是由max函数创建的,10表示每次用max2函数,都要额外加入一个数字10参与运算
max2(5,6,7) #等价于 args=(10,5,6,7) max(*args)

浙公网安备 33010602011771号