1. 程式人生 > >Python全棧開發之---裝飾器

Python全棧開發之---裝飾器

1、裝飾器的形成過程

 1 import time
 2 
 3 def func1():
 4     print('in func1')
 5 
 6 def timer(func):
 7     def inner():
 8         start = time.time()
 9         func()
10         print(time.time() - start)
11     return inner
12 
13 func1 = timer(func1)
14 func1()

礙眼的那句話就是還要在做一次賦值呼叫。。。

你覺得礙眼,python的開發者也覺得礙眼,所以就為我們提供了一句語法糖來解決這個問題!

 1 import time
 2 def timer(func):
 3     def inner():
 4         start = time.time()
 5         func()
 6         print(time.time() - start)
 7     return inner
 8 
 9 @timer   #==> func1 = timer(func1)
10 def func1():
11     print('in func1')
12 
13 
14 func1()
15 
16 裝飾器——語法糖

到這裡,我們可以簡單的總結一下:

  裝飾器的本質:一個閉包函式

  裝飾器的功能:在不修改原函式及其呼叫方式的情況下對原函式功能進行擴充套件

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

 1 import time
 2 def timer(func):
 3     def inner(*args,**kwargs):
 4         start = time.time()
 5         re = func(*args,**kwargs)
 6         print(time.time() - start)
 7         return
re 8 return inner 9 10 @timer #==> func1 = timer(func1) 11 def func1(a,b): 12 print('in func1') 13 14 @timer #==> func2 = timer(func2) 15 def func2(a): 16 print('in func2 and get a:%s'%(a)) 17 return 'fun2 over' 18 19 func1('aaaaaa','bbbbbb') 20 print(func2('aaaaaa')) 21 22 裝飾器——成功hold住所有函式傳參

我們還要在裝飾器上加上一點來完善它:

 1 from functools import wraps
 2 
 3 def deco(func):
 4     @wraps(func) #加在最內層函式正上方
 5     def wrapper(*args,**kwargs):
 6         return func(*args,**kwargs)
 7     return wrapper
 8 
 9 @deco
10 def index():
11     '''哈哈哈哈'''
12     print('from index')
13 
14 print(index.__doc__)
15 print(index.__name__)
16 
17 裝飾器——wraps demo

2、開放封閉原則

  1.對擴充套件是開放的

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

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

  2.對修改是封閉的

    為什麼要對修改封閉呢?

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

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

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

裝飾器的主要功能:

在不改變函式呼叫方式的基礎上在函式的前、後新增功能。

裝飾器的固定格式:

 1 def timer(func):
 2     def inner(*args,**kwargs):
 3         '''執行函式之前要做的'''
 4         re = func(*args,**kwargs)
 5         '''執行函式之後要做的'''
 6         return re
 7     return inner
 8 
 9 裝飾器的固定格式
10 
11 from functools import wraps
12 
13 def deco(func):
14     @wraps(func) #加在最內層函式正上方
15     def wrapper(*args,**kwargs):
16         return func(*args,**kwargs)
17     return wrapper
18 
19 裝飾器的固定格式——wraps版

4、帶引數的裝飾器

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

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

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

 1 def outer(flag):
 2     def timer(func):
 3         def inner(*args,**kwargs):
 4             if flag:
 5                 print('''執行函式之前要做的''')
 6             re = func(*args,**kwargs)
 7             if flag:
 8                 print('''執行函式之後要做的''')
 9             return re
10         return inner
11     return timer
12 
13 @outer(False)
14 def func():
15     print(111)
16 
17 func()
18 
19 帶引數的裝飾器

5、多個裝飾器裝飾同一個函式

有些時候,我們也會用到多個裝飾器裝飾同一個函式的情況。

 1 def wrapper1(func):
 2     def inner():
 3         print('wrapper1 ,before func')
 4         func()
 5         print('wrapper1 ,after func')
 6     return inner
 7 
 8 def wrapper2(func):
 9     def inner():
10         print('wrapper2 ,before func')
11         func()
12         print('wrapper2 ,after func')
13     return inner
14 
15 @wrapper2
16 @wrapper1
17 def f():
18     print('in f')
19 
20 f()
21 
22 多個裝飾器裝飾同一個函式