一、裝飾器的目的

我們需要遵守開放封閉原則。

  開放封閉原則:程式上線以後就應該對修改封閉,對擴充套件開放

  修改封閉:不能修改功能性函式的原始碼

  不能修改功能性函式的呼叫方式

  擴充套件開放:可以為原有的功能新增新功能

 

二、裝飾器的逐步實現

首先,我們定義一個函式

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() 此時我們這樣寫看似在呼叫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')