Python之装饰器(二)
之前总结了装饰器的简单原理,本次主要总结有参函数的装饰。
一、装饰有参函数:add(a, b)
装饰器通过返回包装对象实现间接调用,插入额外功能。如下例,装饰有参函数add(a, b),在函数运行前sleep()一段时间。实际上,add = func = wapper, 所以func()和wapper()需要加上参数,而为了使程序更加有扩展性,可添加可变参数*agrs和 **kwargs。
def delay(func):
def wrapper(*args, **kwargs): # 1
time.sleep(1)
ret = func(*args, **kwargs) # 2
print("delay 1 second before call %s" % func.__name__)
return ret # 原函数返回值
return wrapper
@delay
def add(a, b):
return a + b
二、带参装饰器:@decorator(parameter = value)
@delay_p(parameter='A') #
def add1(a, b):
return a + b
获取被装饰函数的信息,从而可实现不同函数采取不一样的装饰效果。而要将parameter参数传递到装饰器中,再加一层函数来接受参数。类似嵌套函数的概念,执行内函数,先执行外函数。以上带参的装饰器可写成如下调用形式:
delay_p = delay_p(parameter)
add1 = delay_p(add1)
装饰器加一层函数接收参数,其他的与无参装饰器类似。
def delay_p(parameter):
def outer_wrapper(func):
def wrapper(*args, **kwargs): # 1
if parameter == 'A':
time.sleep(5)
ret = func(*args, **kwargs)
print("delay 5 second before call %s" % func.__name__)
else:
time.sleep(4)
ret = func(*args, **kwargs)
print("delay 4 second before call %s" % func.__name__)
return ret
return wrapper
return outer_wrapper
@delay_p(parameter='A')
def add1(a, b):
return a + b
@delay_p(parameter='B')
def add2(a, b):
return a + b
各函数调用结果:
三、@wraps
装饰器(decorator)在实现的时候,被装饰后的函数其实已经是另外一个函数,函数的属性已被装饰器改变。
print(add.__name__, add.__doc__) # wrapper None
print(add1.__name__, add1.__doc__) # wrapper decor
Python的functools包中functools.wraps可消除这样的影响,将原函数对象的指定属性复制给包装函数对象。使其保留原有函数的名称和docstring。如下 # 1处加入 @wraps(func), 运行结果:add1 Docstring add1
from functools import wraps #
def delay_p(parameter):
def outer_wrapper(func):
@wraps(func) # 1
def wrapper(*args, **kwargs):
"""decor"""
if parameter == 'A':
time.sleep(5)
ret = func(*args, **kwargs)
print("delay 5 second before call %s" % func.__name__)
else:
time.sleep(4)
ret = func(*args, **kwargs)
print("delay 4 second before call %s" % func.__name__)
return ret
return wrapper
return outer_wrapper
@delay_p(parameter='A')
def add1(a, b):
"""Docstring add1"""
return a + b