裝飾器
裝飾器顧名思義就是一個有裝飾功能的工具,那麼裝飾器又是用來裝飾什麼的?為什麼要裝飾這個東西?裝飾的目的是什麼呢?本文會一一作答讓小弟一個一個說
開放封閉原則
談及裝飾器就要引申一個概念,那就是開放封閉原則,那麼問題又來了 什麼是開放封閉……好好好,直接說這個,開放封閉本來是兩個對立的概念,也就是說是一對反義詞,那麼為什麼要提出開放封閉原則呢?原因是在日常的開發工作中,一般最初上線的產品的功能是不盡完善的,就是說不夠完美但已經能夠支撐日常使用,其餘的功能可以日後擴充套件,舉例:N年前的QQ和現在的QQ(PS:雖然現在本人不怎麼用了)。在後期擴充套件功能時,因為函式已經是寫好的,而且存在大量呼叫,所以要直接去給函式增添新的功能顯然不現實,所以我們只能新建函式去給原來的函式擴充套件功能(其實這就是一個裝飾器啦)
那麼開放封閉原則到底是什麼? 答案是對原始碼封閉,對新功能開放
-
封閉原則:不要改變原始碼
-
開放原則:能增加一些額外的功能
如果還有客觀對開放封閉原則似知似解的話,沒關係接著往下看,不影響您食用本文,因為Python裝飾器本身就是對開放封閉原則完美的詮釋
裝飾器初識
不低調的說,裝飾器就是一個函式,名字本來很高大上,但本質就是一個函式,裝飾器函式的功能就是要裝飾一個函式,在不改變被裝飾函式的原始碼及呼叫方式的前提下,為其增加額外的功能。是不是有點門道了,是不是覺得這玩意也沒啥啦,真是優秀的同學。
程式碼show(技術部落格不寫程式碼乾白話說出去丟人)
def warpper(f): #定義一個函式(裝飾器),傳入的引數是被修飾的函式的函式名
def inner(*args,**kwargs): #巢狀一個記憶體函式,這個函式主題才是執行被裝飾函式原始碼的關鍵
'''這塊可以加要在被裝飾函式執行之前的操作哈'''
ret = f(*args,**kwargs) #這裡的形參我會在下面說明
'''這裡可以寫被裝飾函式之後的,兄嘚,別客氣,想加啥方法加什麼'''
return ret #這裡的返回值如果我一會兒不忘的話也會在下面說明
return inner
@warpper #這個叫語法糖,嗯……可以吃(可能老外命名的時候就是這麼想的),結構是@加函式名,作用下面會說明
def func():
print('我就是那個被裝飾的函式')
簡單說明
因為本人比較懶,所以原諒我直接把程式碼甩上去了,後面有註釋,看懂了的大佬可以say goodbye啦,想打我的接著聽我白話,那我就把備註再重複一遍,哈哈,你也看到了,裝飾器用到了函式的巢狀(再具體點就是閉包,要問什麼是閉包,百度吧,哈哈),首先外層函式接收到一個函式名,然後返回值是內層函式的函式名;再來內層函式可以接收引數,其中ret = f(*args,**kwargs)
有兩個作用,一是執行了傳入的函式,也就是執行了被修飾的函式,二是將返回值賦給了一個變數,此處要說明一下,對被修飾的函式功能的擴充套件要寫在這裡哦,最後 ret作為內層函式的返回值返回給函式執行者。
語法糖
@warpper
這東西和 func = wrapper(func)是一樣的,也就是說最後三行程式碼可以這樣寫
#@warpper
def func():
print('我就是那個被裝飾的函式')
func = wrapper(func) #注意奧,這玩意要寫在被裝飾函式的下邊,語法糖才寫上邊
至於為什麼要寫著東西,或者為什麼要用語法糖?請聽下回分解~~~,收起你滴拳頭,是這樣,我剛開始的時候談到了,裝飾器是要在不改變原始碼和其呼叫方式的前提下給其增加新的功能,注意到了麼 呼叫方式 嗯……沒錯就是呼叫方式,如果我不這樣寫那我是不是要wrapper(func)()
這樣去呼叫啊,是不是有點繞了,但是我把wrapper(func)
賦值給了一個和被裝飾函式同名的變數,那我此時要怎麼呼叫,是不是就是func()
,這樣就滿足了開放封閉原則,完美!其實本質就是要把裝飾器“偽裝”成原函式,包括呼叫方式、引數、返回值,裝就要裝的像一點,對吧。
裝飾帶引數的裝飾器
def wrapper(f):
def inner(*args,**kwargs):
f(*args,**kwargs)
return inner
@wrapper
def func(a,b):
print(a,b)
函式func中有兩個形參a和b,說一下這兩個引數在裝飾器中的旅程,函式inner的萬能引數接收到a和b打包,然後inner函式充當中間商將打包後的元組給了f,在f中打散又成了變數a和b,在裝飾器時就不會影響傳參了,這就是裝飾帶引數的函式
裝飾有返回值的函式
def wrapper(f):
def inner():
ret = f()
return ret
return inner
@wrapper
def func():
return('我不管,我最帥')
哈哈,這段程式碼中有我的心聲,你們都懂的,很簡單,裝飾有返回值的引數,在inner函式中將f()賦值給ret,這樣ret就接收到了返回值,再將ret返回給inner(),以此來達到“模擬”被裝飾函式的返回值,也可以說是通過這種方法來拿到被裝飾函式的返回值。
好,到此對Python裝飾器應該有那麼一丟丟的認識了哈,我不管,就得有認識。下面的內容和文章關係不大哈
第一篇正經寫的文章,可能文章內容表達不盡如人意的正經哈,但初心是好的,就是分享知識,分享心得嘛,嗯,不管怎麼說,我還是很欣慰的對自己,哈哈,能有人從中有收穫就更perfect嘍