裝飾器本身是利用閉包實現的,因此只有真正學會了閉包中的知識點才能完全理解裝飾器的語法。
試想乙個問題:在乙個工程中有乙個函式func(),現在有乙個需求是func()現在本身不能滿足的,因此需要重新實現func()的功能。這是正常的思路,也是可行的,但是卻違背了開發中的「開放、封閉」原則。
封閉:函式本身的功能不能隨便更改。因為如果這個函式在功能中被呼叫了多次,現在因其中某乙個地方就要改這個函式中實現,那麼極有可能會對其他地方產生影響。
開放:在開發過程中如果有新的需求應盡量在不修改原有**的前提下實現新的需求,這樣能避免對原來的功能改動。
裝飾器就是在不修改原有函式的實現和呼叫的前提下實現對現有函式功能的拓展。
def f1(func):
print('in f1')
def f1_inner():
print('in f1_inner')
func()
return f1_inner
def f():
print('in f')
if __name__ == '__main__':
x = f1(f)
print(type(x))
print(x)
print('*' * 10)
x()結果:in f1
.f1_inner at 0x01068db0>
**********
in f1_inner
in f
以上的例子意思是有乙個閉包f1(func),需要func這個引數,目前還不知道func這個引數是什麼型別。在閉包f1_inner中有一句:func(),由這樣的語法呼叫我們可以推測出引數func其實是乙個函式的引用。函式f()是乙個普通的函式。現在我們想實現的是用函式f1()的功能來裝飾函式f,即在依次列印:in f1 in f1_inner in f。
直接呼叫閉包f1(f),將函式f()作為引數傳輸,得到f1(f)的返回值x,接著列印了x型別和值(這是為了方便理解)。最後呼叫了x()便實現了我們想要的列印效果。
以上例子是利用閉包實現裝飾器的基本原理。
#f1是裝飾器
def f1(func):
print('in f1')
def f1_inner():
print('in f1_inner')
func()
return f1_inner
#f是被裝飾函式,只要在函式定義前加:@裝飾器名稱
@f1def f():
print('in f')
if __name__ == '__main__':
#正常呼叫被裝飾的函式f即可
f()結果:in f1
in f1_inner
in f
通過以上的**注釋和列印仔細品味一下,裝飾器的基礎就是這樣:
閉包實現乙個裝飾器
在被裝飾函式定義前加@裝飾器
正常呼叫被裝飾的函式
就以上的例子來說,裝飾器是什麼時候被執行的?實在呼叫f()的時候嗎?請大家自己嘗試一些,不呼叫函式f(),「in f1」也是正常列印的,由此可以得出裝飾器是在直譯器第一次解釋到@符號時執行的。
Python學習之路 裝飾器(2)
coding utf 8 def f1 func print in f1 def f1 inner print in f1 inner func return f1 inner def f2 func print in f2 def f2 inner print in f2 inner func r...
Python學習之路 裝飾器(3)
上兩篇提到的裝飾器的例子中,被修飾的函式沒有引數,那麼如果修飾帶引數的裝飾器又該如何書寫呢?coding utf 8 def f1 func print in f1 def f1 inner print in f1 inner func return f1 inner f1def f a,b pri...
Python學習之路 裝飾器(4)
函式通常都是帶有返回值的,當裝飾器修飾帶有返回值的函式時該怎麼實現呢?coding utf 8 def f1 func print in func def f1 inner print in f1 inner value func return value return f1 inner f1def...