1. 程式人生 > >python函式的裝飾器

python函式的裝飾器

裝飾器

裝飾器的本身也是一個函式,它可以讓其他函式在不需要做任何程式碼變動的前提下,增加額外的功能,裝飾器的返回值也是一個函式物件,就是函式裝飾函式的這樣的一個過程。
裝飾器的應用場景:比如插入日誌,效能測試,事務處理,快取等等場景。

裝飾器的形成

比如,測試一個函式的執行時間,在不改變原有程式碼的情況下,實現這個功能

簡單裝飾器

import time
def func1():
    print('this is func1')
def timer(func):
    def inner():
        start = time.time()
        func()
        print(time.time() - start)
    return inner
func1 = timer(func1)
func1()

但是這樣還是有一個不好的地方,就是隻要我們要實現這個功能,就有有這樣一句話func1 = timer(func1),這樣就會有點麻煩:就產生了一個叫語法糖的東東,是什麼呢?

語法糖

import time
def timer(func):
    def inner():
        start = time.time()
        func()
        print(time.time() - start)
    return inner
    
@timer   #==> func1 = timer(func1)
def func1():
    print('in func1')
    
func1()

帶引數的裝飾器

def timer(func):
    def inner(a):
        start = time.time()
        func(a)
        print(time.time() - start)
    return inner

@timer
def func1(a):
    print(a)

func1(1)

帶動態引數的裝飾器

import time
def wrapper(func):
    def inner(*args, **kwargs): 
        start_time = time.localtime()
        time_now = time.strftime("%Y-%m-%d %H:%M:%S", start_time)
        with open('log', encoding='utf-8', mode='a') as f1:
            f1.write("在%s是時間,執行了%s函式\n" % (time_now, func._name_))
            ret = func(*args, **kwargs)
            return ret
        return inner()
 
@wrapper
def func1():
    time.sleep(1)
    print(555)
@wrapper
def func2():
     time.sleep(2)
     print(666)
func1()
func2()

檢視函式資訊的方法

def index():
    '''這是一個主頁資訊'''
    print('from index')
 
print(index.__doc__)    #檢視函式註釋的方法
print(index.__name__)   #檢視函式名的方法

例如:

from functools import wraps
 
def demo(func):
    @wraps(func)    #@wraps要載入最內層函式的正上方
    def wrapper(*args, **kwargs):
        return func(*args, **kwargs)
    return  wrapper
@demo
def index():
    '''你以為這是什麼就是個註釋而已'''
    print('this is index')
print(index.__doc__)
print(index.__name__)

開放封閉的原則

裝飾器遵循開放封閉的原則
1.對擴充套件是開放的,也就是說,必須允許程式碼擴充套件、新增新功能。
2.對修改是封閉的,儘可能的如果再次修改,不會影響別人的使用。

裝飾器的主要功能和固定結構

'''裝飾器的固定結構'''
def timer(func):
    def inner(*args, **kwargs):
        '''執行函式之前要做的'''
        re = func(*args, **kwargs):
        return re
'''wraps版'''
from functools import wraps
 
def demo(func):
    @wraps(func)    #@wraps要載入最內層函式的正上方
    def wrapper(*args, **kwargs):
        return func(*args, **kwargs)
    return  wrapper

帶引數的裝飾器

	
def outer(flag):
    def timer(func):
        def inner(*args, **kwargs):
            if flag:
                print('執行函式之前要做的')
            re = func(*args, **kwargs)
             
            if flag:
                print('執行函式之後要做的')
            return re
        return inner
    return timer
@outer(False)
def func():
    print('6666')
 
func()

多個裝飾器裝飾一個函式

def wrapper1(func):
    def inner():
        print('wrappers1,before func')
        func()
        print('wrappers1,after func')
    return inner
 
def wrapper2(func):
    def inner():
        print('wrappers2,before func')
        func()
        print('wrappers2,after func')
    return inner
 
@wrapper1
@wrapper2
def f():
    print('in f')
 
f()