在python中,对于一个函数而言,如果想要增强它的功能而又不在其函数体内增加内容,以保证函数的易读性,就可以使用装饰器。常见的装饰器为两种,分别为无参装饰器和有参装饰器。
1、无参装饰器
本文以简单的求和函数为例,对于一个求和函数,在不改变函数内语句的情况下,在求和之前对函数进行增强,如对输入参数进行判断、对输出结果的格式进行转换等,都可以使用函数装饰器来实现:
def logger(fn):
def wrapper(*args, **kwargs):
'''前方功能增强'''
result = fn(*args, **kwargs)
'''后方功能增强'''
return result
return wrapper
@logger
def add(x, y):
return x + y
在上例中,logger函数为无参装饰器的通用书写程序,只需要将前方功能增强及后方功能增强更换为所需代码,就可以完成一个装饰器。
对于无参装饰器而言,未在add函数代码内做任何修改,然而通过对函数的装饰,add变量名默认已经指向了内层函数wrapper的入口,而wrapper内部的函数fn指向原函数add的函数入口,所以,用户在使用add函数时,实际过程时运行了wrapper函数,咋wrapper函数内又调用了原来的add函数。
2、带参装饰器
带参装饰器在本质上是对原装饰器的一个封装,最外层函数返回一个装饰器,以此来解决装饰器与原函数之间的参数传递问题。
def copy_propoerties(scr):
def _copy(dest):
dest.__name__ = scr.__name__
dest.__doc__ = sct.__doc__
return dest
return _copy
def logger(fn):
@copy_properties(fn)
def wrapper(*args, **kwargs):
'''begin'''
result = fn(*args, **args)
'''end'''
return result
return wrapper
@logger
def add(x, y):
return x + y
以上代码所示,使用装饰器可以将原函数的功能增强,同时,用户在看add函数的name、doc等属性数据时,也会显示add函数的内容。而此项功能在functools模块也有
import functools
def logger(duration, funsc=lambda name,duration: print('{} took {}s'.format(name, duration))):
def _logger(fn):
@functools.wraps(fn)
def wrapper(*arges, **kwarges):
start = datetime.datetime.now()
ret = fn(*arges, **kwarges)
delta = (datetime.datetime.now() - start).total_seconds()
if delta < duration:
funsc(fn.__name__,duration)
return ret
return wrapper
return _logger
@logger(5)
def add(x,y):
return x + y
有以上代码可以看出,functools.wraps()装饰器与自己实现的装饰器具有同样的功能