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
"""