python装饰器
举例一个加法函数,想要增强它的功能,能够输出被调用过,以及调用的参数信息def add(x,y):
return x+y
#增强信息输出功能
def add(x,y):
print("call add,x+y"") #输出到控制台
return x+y
上面加法函数虽然实现了需求但是打印语句耦合性太高,加法函数属于业务功能,而输出信息的功能非业务功能代码放到一起不好
为了做到业务分离,如下可以实现原函数的增强
def add(x,y):
return x+y
def logger(fn,x,y):
print("start")
x=fn(x,y)
print("end")
return x
print(logger(add,4,5))
#但是这种不够灵活
def add1(x,y,z):
return x+y+z
def add2(x,y,*args,z):
pass
#再有上面这样的函数参数就不能通用 改造
def logger(fn,*args,**kwargs): #*args(元组),**kwargs(字典) 可变形参 *args 顺序参数组成的元组 **kwargs keyword形式
print("start")
x=fn(*args,**kwargs) #解构赋值
print("end")
return x
但是这种不顺眼能不能进行柯里化呢
def logger(fn):
def_logger(*args,**kwargs):
print("start")
x=fn(*args,**kwargs)
print("end")
return x
return _logger
#调用
logger(add)(4,5)
add=logger(add)
add(4,5)
由于形成了闭包传进去的函数被保留了所以这么写没有问题
#装饰器
@logger # 自动找下一行获取函数名 add=logger(add)
def add(x,y):
return x+y
#@logger 相当于 add=logger(add) 这就是装饰器
文档字符串
必须放在函数第一行def add(x,y):
""" this is a function of addition""" #文档字符串
pass
带参数装饰器
上面的装饰器代码改变了add函数的名字def copy_propertles(src,dst):
dst.__name__=src.__name__
dst.__doc__=src.__name__
def logger(fn):
def _logger(*args,**kwargs):
print("start")
x=fn(*args,**kwargs)
print("end")
return x
copy_propertles(fn,_logger)
return _logger
@logger
def add(x,y):
return x+y
这样实现了add还保有原名字
把这个copy函数改写成装饰器
def copy_propertles(src):
def wrapper(dst):
dst.__name__=src.__name__
dst.__doc__=src.__name__
return dst
return wrapper
def logger(fn):
@copy_propertles(fn) #相当于 copy_propertles(fn)(_logger) ==> wrapper(_logger)
def _logger(*args,**kwargs):
print("start")
x=fn(*args,**kwargs)
print("end")
return x
copy_propertles(fn,_logger)
return _logger
@logger
def add(x,y):
return x+y
copy_propertles函数就是一个带参装饰器
官方模块实现copy函数
add.wrapped 保留原函数
functools模块
- partial方法偏函数,把函数部分的参数固定下来,相当于为部分参数添加一个固定的默认值,返回一个新函数,是原函数的封装
import functools
def add(x,y)->int:
return x+y
newadd=functools.partial(add,y=5)
print(newadd(5))
print(newadd(5,y=7))