裝飾器的實現,類裝飾器
阿新 • • 發佈:2019-01-04
一、裝飾器的目的
我們需要遵守開放封閉原則。
開放封閉原則:程式上線以後就應該對修改封閉,對擴充套件開放
修改封閉:不能修改功能性函式的原始碼
不能修改功能性函式的呼叫方式
二、裝飾器的逐步實現
首先,我們定義一個函式
import time, random def msg(): print('I have something to tell you, please wait a moment.') time.sleep(random.randint(1, 5)) print('I like you.') msg()
該函式會隨機休眠1-5秒鐘。
現在,我們想要給該函式增加一個計時的功能,看看函式具體運行了多久。
import time, random def msg(): print('I have something to tell you, please wait a moment.') time.sleep(random.randint(1, 5)) print('I like you.') start_time = time.time() msg() stop_time = time.time() print('Run time is %s' % (stop_time - start_time))
並且如果要重複使用計時功能,就要寫重複程式碼,所以我們想到了將計時功能封裝成一個函式
def wrapper(): start = time.time() msg() stop = time.time() print('Run time is %s' % (stop - start)) wrapper()
我們將wrapper函式寫死了,只能對內部呼叫的msg函式進行計時,使用閉包函式
def timmer(func): def wrapper(): start= time.time() func() stop = time.time() print('Run time is %s' % (stop - start)) return wrapper # 將wrapper函式的記憶體地址作為返回值返回。 msg = timmer(msg) # 作為引數的msg是我們定義的msg函式的記憶體地址 # 作為變數名的msg是指向wrapper函式的記憶體地址
這樣子我們就實現了偷樑換柱,在外觀上沒有更改msg函式的呼叫方式。
當傳入的函式有引數或者有返回值時
def timmer(func): def wrapper(*args, **kwargs): strat_time = time.time() res = func(*args, **kwargs) stop_time = time.time() return res return wrapper
裝飾器的使用方法:語法糖
import time, random def timmer(func): def wrapper(*args, **kwargs): strat_time = time.time() res = func(*args, **kwargs) stop_time = time.time() return res return wrapper @timmer def msg(): print('I have something to tell you, please wait a moment.') time.sleep(random.randint(1, 5)) print('I like you.') msg()
含參裝飾器,含參裝飾器是一個三層的閉包函式
import time def timemer(partment): def func(func_1): def wrapper(*args,**wkargs): if partment=='task1': start = time.time() func_1(*args, **wkargs) stop = time.time() print("the task1 run time is :", stop - start) elif partment=='task2': start = time.time() func_1(*args, **wkargs) stop = time.time() print("the task2 run time is :", stop - start) return wrapper return func @timemer(partment='task1') def task1(): time.sleep(2) print("in the task1") @timemer(partment='task2') def task2(): time.sleep(2) print("in the task2") task1() task2()
類實現的含參裝飾器
from functools import wraps
class decorate: def __init__(self, name): self.name = name # 裝飾器的引數
def __call__(self, func): @wraps(func) def deco(*args, **kwargs): if self.name == 'Admin': passelif self.name == 'Student': passelif self.name == 'Teacher': passreturn func(*args, **kwargs) return deco
@decarate('Admin')