1. 程式人生 > >python之裝飾器 python之裝飾器

python之裝飾器 python之裝飾器

---恢復內容開始---

python之裝飾器

 

一,什麼是裝飾器?

裝飾器本質上就是一個python閉包函式,他可以讓其他函式在不需要做任何程式碼變動的前提下增加額外的功能裝飾器的返回值也是一個函式物件。

裝飾器的應用場景:比如插入日誌,效能測試,事務處理,快取等等場景。

二,裝飾器的形成過程。

現在我有一個需求,我想讓你測試這個函式的執行時間,在不改變這個函式程式碼的情況下:

# import time
# def func1():
#     print('in func1')
#
# def timer(f):
# def inner(): # start_time = time.time() # f() # end_time = time.time() # return inner # func1 = timer(func1) # func1()

 

但是如果有多個函式,我都想讓你測試他們的執行時間,你每次是不是都得func1 = timer(func1)?這樣還是有點麻煩,因為這些函式的函式名可能是不相同,有func1,func2,graph,等等,所以更簡單的方法,python給你提供了,那就是語法糖。

import time
def timer(f):
    def inner():
        start_time = time.time()
        f()
        end_time = time.time()
        print(end_time - start_time)
    return inner
@timer  #==  func1 = timer(func1)
def func1():
    print('in func1')
    time.sleep(0.5)

func1()

 

 剛剛我們討論的裝飾器都是裝飾不帶引數的函式,現在要裝飾一個帶引數的函式怎麼辦呢?

import time
def timer(f):
    def inner(a):
        start_time = time.time()
        f(a)
        end_time = time.time()
        print(end_time - start_time)
    return inner

@timer
def func1(a):
    print(a)
    time.sleep(0.2)

func1(9)
#裝飾器——帶引數的裝飾器

 

import time
def timer(f):
    def inner(*args, **kwargs):  #引數聚合過程
        start_time = time.time()
        ret = f(*args, **kwargs)  #引數打散過程
        end_time = time.time()
        return ret
    return inner
@timer  # ==> func1 = timer(func1)
def func1(a, b):
    print('in func1')
@timer  # ==>  func2 = timer(func2)
def func2(a):
    print('in func2 and get a : %s' % a)
@timer  # ==>   func3 = timer(func3)
def func3(a, b, c, d=3):
    print(a, b, c, d)
func1(1, 2)
func2(1)
func3(1, 2, 3, 5)

 

上面的裝飾器已經非常完美了,但是有我們正常情況下檢視函式資訊的方法在此處都會失效:

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

 

如何解決呢?

from functools import wraps
def deco(f):
    @wraps(f) # 加在最內層函式正上方
    def wrapper(*args, **kwargs):
        return f(*args, **kwargs)
    return wrapper

@deco
def index():
    '''嘻嘻哈哈'''
    print('from index')
print(index.__doc__)
print(index.__name__)

 

三,開放封閉原則。

1.對擴充套件是開放的

    為什麼要對擴充套件開放呢?

    我們說,任何一個程式,不可能在設計之初就已經想好了所有的功能並且未來不做任何更新和修改。所以我們必須允許程式碼擴充套件、新增新功能。

  2.對修改是封閉的

    為什麼要對修改封閉呢?

    就像我們剛剛提到的,因為我們寫的一個函式,很有可能已經交付給其他人使用了,如果這個時候我們對其進行了修改,很有可能影響其他已經在使用該函式的使用者。

裝飾器完美的遵循了這個開放封閉原則。

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

def timer(f):
    def inner(*args, **kwargs):
        '''執行函式前要做的'''
        ret = f(*args, **kwargs)
        '''執行函式之後要做的'''
        return ret
    return inner

 

from functools import wraps
def deco(f):
    @wraps(f)
    def wrapper(*args, **kwargs):
        return f(*args, **kwargs)
    return wrapper

 

五,帶引數的裝飾器。

假如你有成千上萬個函式使用了一個裝飾器,現在你想把這些裝飾器都取消掉,你要怎麼做?

一個一個的取消掉? 沒日沒夜忙活3天。。。

過兩天你領導想通了,再讓你加上。。。

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

@outer(False)
def func():
    print(111)

func()

 

六,多個裝飾器裝飾一個函式。

def wrapper1(func):
    def inner():
        print('wrapper1, before func')
        func()
        print('wrapper1, after func')
    return inner

def wrapper2(func):
    def inner():
        print('wrapper2, before func')
        func()
        print('wrapper2, after func')
    return inner

@wrapper2
@wrapper1
def f():
    print('in f')

f()
# wrapper2, before func
# wrapper1, before func
# in f
# wrapper1, after func
# wrapper2, after func

 

---恢復內容結束---

一,什麼是裝飾器?

裝飾器本質上就是一個python閉包函式,他可以讓其他函式在不需要做任何程式碼變動的前提下增加額外的功能裝飾器的返回值也是一個函式物件。

裝飾器的應用場景:比如插入日誌,效能測試,事務處理,快取等等場景。

二,裝飾器的形成過程。

現在我有一個需求,我想讓你測試這個函式的執行時間,在不改變這個函式程式碼的情況下:

# import time
# def func1():
#     print('in func1')
#
# def timer(f):
#     def inner():
#         start_time = time.time()
#         f()
#         end_time = time.time()
#     return inner
# func1 = timer(func1)
# func1()

 

但是如果有多個函式,我都想讓你測試他們的執行時間,你每次是不是都得func1 = timer(func1)?這樣還是有點麻煩,因為這些函式的函式名可能是不相同,有func1,func2,graph,等等,所以更簡單的方法,python給你提供了,那就是語法糖。

import time
def timer(f):
    def inner():
        start_time = time.time()
        f()
        end_time = time.time()
        print(end_time - start_time)
    return inner
@timer  #==  func1 = timer(func1)
def func1():
    print('in func1')
    time.sleep(0.5)

func1()

 

 剛剛我們討論的裝飾器都是裝飾不帶引數的函式,現在要裝飾一個帶引數的函式怎麼辦呢?

import time
def timer(f):
    def inner(a):
        start_time = time.time()
        f(a)
        end_time = time.time()
        print(end_time - start_time)
    return inner

@timer
def func1(a):
    print(a)
    time.sleep(0.2)

func1(9)
#裝飾器——帶引數的裝飾器

 

import time
def timer(f):
    def inner(*args, **kwargs):  #引數聚合過程
        start_time = time.time()
        ret = f(*args, **kwargs)  #引數打散過程
        end_time = time.time()
        return ret
    return inner
@timer  # ==> func1 = timer(func1)
def func1(a, b):
    print('in func1')
@timer  # ==>  func2 = timer(func2)
def func2(a):
    print('in func2 and get a : %s' % a)
@timer  # ==>   func3 = timer(func3)
def func3(a, b, c, d=3):
    print(a, b, c, d)
func1(1, 2)
func2(1)
func3(1, 2, 3, 5)

 

上面的裝飾器已經非常完美了,但是有我們正常情況下檢視函式資訊的方法在此處都會失效:

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

 

如何解決呢?

from functools import wraps
def deco(f):
    @wraps(f) # 加在最內層函式正上方
    def wrapper(*args, **kwargs):
        return f(*args, **kwargs)
    return wrapper

@deco
def index():
    '''嘻嘻哈哈'''
    print('from index')
print(index.__doc__)
print(index.__name__)

 

三,開放封閉原則。

1.對擴充套件是開放的

    為什麼要對擴充套件開放呢?

    我們說,任何一個程式,不可能在設計之初就已經想好了所有的功能並且未來不做任何更新和修改。所以我們必須允許程式碼擴充套件、新增新功能。

  2.對修改是封閉的

    為什麼要對修改封閉呢?

    就像我們剛剛提到的,因為我們寫的一個函式,很有可能已經交付給其他人使用了,如果這個時候我們對其進行了修改,很有可能影響其他已經在使用該函式的使用者。

裝飾器完美的遵循了這個開放封閉原則。

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

def timer(f):
    def inner(*args, **kwargs):
        '''執行函式前要做的'''
        ret = f(*args, **kwargs)
        '''執行函式之後要做的'''
        return ret
    return inner

 

from functools import wraps
def deco(f):
    @wraps(f)
    def wrapper(*args, **kwargs):
        return f(*args, **kwargs)
    return wrapper

 

五,帶引數的裝飾器。

假如你有成千上萬個函式使用了一個裝飾器,現在你想把這些裝飾器都取消掉,你要怎麼做?

一個一個的取消掉? 沒日沒夜忙活3天。。。

過兩天你領導想通了,再讓你加上。。。

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

@outer(False)
def func():
    print(111)

func()

 

六,多個裝飾器裝飾一個函式。

def wrapper1(func):
    def inner():
        print('wrapper1, before func')
        func()
        print('wrapper1, after func')
    return inner

def wrapper2(func):
    def inner():
        print('wrapper2, before func')
        func()
        print('wrapper2, after func')
    return inner

@wrapper2
@wrapper1
def f():
    print('in f')

f()
# wrapper2, before func
# wrapper1, before func
# in f
# wrapper1, after func
# wrapper2, after func