1.装饰器本质是一个函数,该函数的参数是另一个函数。目的增加函数的功能。
2.@
语法只是将函数传入装饰器函数,并无神奇之处。
一、带参数的装饰器(函数)
特点两层函数
import functools
def log(func): #第一层
@functools.wraps(func) #为了解决被装饰函数的名称变化的问题
def wrapper(*args, **kwargs): #第一层
print('call %s():' % func.__name__)
print('args = {}'.format(*args))
return func(*args, **kwargs)
return wrapper
使用装饰器有两种方式,第一种也就加一个@符号就用了。第二种就是两次调用。
@log
def test(p):
print(test.__name__ + " param: " + p)
def test(p):
print(test.__name__ + " param: " + p)
wrapper = log(test)
wrapper("I'm a param")
二、带参数的装饰器 (函数)
特点 是三层函数,为啥三层,因为要传除了被装饰的func函数外,还要传其他参数。
import functools
def log_with_param(text): # 第一层
def decorator(func): # 第二层
@functools.wraps(func)
def wrapper(*args, **kwargs): # 第三层
print('call %s():' % func.__name__)
print('args = {}'.format(*args))
print('log_param = {}'.format(text))
return func(*args, **kwargs)
return wrapper
return decorator
@log_with_param("param")
def test_with_param(p):
print(test_with_param.__name__)
理解:
decorator = log_with_param("param")
wrapper = decorator(test_with_param)
wrapper('实际的参数')
使用
test_with_param('实际的参数') #加了装饰器的函数,调用还是一样调用,但是该函数增加了装饰器 的功能
附上完整的两个例子
import functools
def log(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
print('call %s():' % func.__name__)
print('args = {}'.format(*args))
return func(*args, **kwargs)
return wrapper
@log
def test(p):
print(test.__name__ + " param: " + p)
test("实际参数")
# 运行信息如下:
"""
call test():
args = 实际参数
test param: 实际参数
"""
import functools
def log(text):
print(text)
def decorator(func):
@functools.wraps(func)
def wrapper(*args,**kwargs):
res = func(*args,**kwargs)
return res
return wrapper
return decorator
@log('装饰器参数')
def test(text):
print(text)
#调用
test('我是被装饰器的函数的参数')
三、多层装饰器
def first_decorator(func):
print('--first--')
def first_wrapper(*args, **kwargs):
print('------first---%s---' % func.__name__)
return func(*args, **kwargs)
return first_wrapper
def second_decorator(func):
print('--second--')
def second_wrapper(*args, **kwargs):
print('------second---%s---' % func.__name__)
return func(*args, **kwargs)
return second_wrapper
@first_decorator
@second_decorator
def test_func_1():
print('excute %s' % inspect.stack()[0][3])
def timeit(func):
def wrapper(*args, **kwargs):
start = time.time()
ret = func(*args, **kwargs)
cost = time.time() - start
print("cost %f second " % cost)
return ret
return wrapper
def delay(sec):
def wrapper(func):
def _wrapper(*args, **kwargs):
time.sleep(sec)
ret = func(*args, **kwargs)
print("delay %d seconds to call %s" % (sec, func.__name__))
return ret
return _wrapper
return wrapper
@timeit
@delay(2)
def add(a, b):
return a + b
if __name__ == "__main__":
add(1, 2)
"""
delay 1 seconds to call add
cost 2 second
"""