1、裝飾器
在不改變源碼的情況下修改已經存在的函數,例如增加調試信息,增加日誌記錄,查看傳入參數等。
裝飾器實際上是一個將一個函數作爲參數並且返回另一個函數的函數
2、裝飾器的使用
- 在需要裝飾的函數前添加裝飾器的名字 @decoratro_name
- 可以通過人工賦值即普通函數調用的方式
==推薦使用第一種方式使用裝飾器,容易理解且簡單方便==
3、示例
(1)、通過裝飾器打印輸出函數名字同時記錄函數開始和結束時間
import datetime
def func_time(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
print('Running function:', func.__name__)
print('start time:',datetime.datetime.now().microsecond)
result = func(*args, **kwargs)
print('end time:',datetime.datetime.now().microsecond)
return result
return wrapper
@func_time
def my_pow(x,y):
return pow(x,y)
print(my_pow(1111,10011))
(2)、裝飾器本身需要傳入參數的例子
import functools
def log(text):
def decorator(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
print('%s %s()' % (text, func.__name__))
return func(*args, **kwargs)
return wrapper
return decorator
@log('execute')
def now():
print('2018-5-29')
now()
print(now.__name__)
注意:代碼中 @functools.wraps(func)的作用是將原始函數的name屬性複製到wrapper中,否則調用now.name會返回wrapper而不是now,這將導致一些依賴函數簽名的代碼執行會出錯
(3)、同一個函數可以有多個裝飾器
import functools
def document_it(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
print('Running function:', func.__name__)
print('Positional arguments:', args)
print('Keyword arguments:', kwargs)
result = func(*args, **kwargs)
print('result:', result)
return result
return wrapper
def square_it(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
result = func(*args, **kwargs)
return result*result
return wrapper
@document_it
@square_it
def add_ints(x, y):
return x+y
print(add_ints(1,5))
#執行結果爲:
#Running function: add_ints
#Positional arguments: (1, 5)
#Keyword arguments: {}
#result: 36
#36
#將裝飾器順序更換
@square_it
@document_it
def add_ints(x, y):
return x+y
print(add_ints(1,5))
#執行結果爲:
#Running function: add_ints
#Positional arguments: (1, 5)
#Keyword arguments: {}
#result: 6
#36
注意:靠近函數定義的裝飾器會先執行,然後依次執行上面的。