python-裝飾器
一、介紹
首先我們先來看一個簡單的例子,在基礎平臺中有一個home()和tv()函數,在業務平臺中調用此函數時,給出了響應的打印內容:
基礎平臺: def home(): print(‘welcome to home page‘) def tv(name): print(‘welcome to tv page‘) 業務平臺A: home() tv() 業務平臺B: home() tv()
但是,在後續的需求中規定,在調用此函數時,還需要進行一個用戶驗證
因此程序猿小A的做法是和每個業務部門交涉,每個業務部門自己寫代碼,在調用基礎平臺的時候,先進行驗證:
基礎平臺: def home(): print(‘welcome to home page‘) def tv(name): print(‘welcome to tv page‘) 業務平臺A: #驗證 home() tv() 業務平臺B: #驗證 home() tv()
小A當天被開除了。。。
後來程序猿小B接手了這份工作,小B的做法是在基礎平臺中加入驗證:
基礎平臺: def home(): #驗證 print(‘welcome to home page‘) def tv(name): #驗證 print(‘welcome to tv page‘) 業務平臺A: home() tv() 業務平臺B: home() tv()
小B的做法相比於小A來說,好了一點,避免了業務平臺的修改,老板為了獎勵小B,因此在一周後把小B開除了。。。
因為小B改動了源代碼
此後,程序猿小C又接受了這個工作。。。
小C說:
寫代碼要滿足以下下兩個原則:
封閉:已實現的功能代碼不允許被修改
開放:已實現的功能代碼可以被擴展:
因此,小C打算在此處使用了裝飾器的功能(見下文)
總結:
裝飾器本質上是一個函數,可以在其他函數不做任何代碼變動的情況下,提供一些擴展的功能
二、簡單裝飾器的使用
小C對代碼做出了如下修改(拿tv方法舉例):
def login(func): #定義了一個登錄驗證的方法 print(‘登錄驗證成功‘) #假設此處就是一個驗證功能 return func def tv(): print(‘welcome to tv page‘ ) tv=login(tv) #對tv進行了賦值,此時還沒執行tv方法,只是把該方法放入到了內存中 tv() ---執行結果--- 登錄驗證成功 welcom to tv page
該代碼是如何實現驗證的呢,步驟如下:
①執行login(tv)時,先不執行tv()方法,只是把tv()方法到了內存中,然後執行login()
②在login()中進行登錄驗證,之後返回tv()的內存地址,此時tv()還未執行
③把tv()的內存地址重新賦值給tv,此時tv變量的值依舊為tv()方法的內容
④通過調動tv()執行tv()方法
再經過一些細小的調整,可以寫成如下的形式:
def login(func): print(‘登錄驗證成功‘) return func @login def tv(): print(‘welcome to tv page‘ ) tv()
其中, @XXX 語法,就是一個裝飾器,也稱為“語法糖”
至此,一個簡單的裝飾器雛形已經完成
但是,此處依舊有一個缺點,那就是 即使業務方沒有調用tv(),代碼中也依舊會執行login()中的驗證,為了讓login()中的驗證
不預先執行,因此小C繼續對代碼進行調整
def login(func): def inner(): print(‘登錄驗證成功‘) func() return inner @login def tv(): print(‘welcome to tv page‘ ) tv()
此處實現驗證功能的步驟如下:
①調用login()方法,返回inner方法的內存地址,此時func的值為tv()內存地址即內容為:
def tv(): print(‘welcome to tv page‘ )
②把inner方法的內存地址賦值給了變量tv
③調用tv(),因為tv的值已經為inner的內存地址,因此調用的是inner()方法
④實現inner()中的驗證功能
⑤驗證成功後,執行inner()中的func(),打印出‘welcome to tv page’
至此,一個簡單的裝飾器才算真正完成
python-裝飾器