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