裝飾器實際上就是一個方法,可是他能夠修飾其餘的方法或者類,咱們定義好一個方法或者類,在他以前使用裝飾器能夠實現咱們想要的效果,好比咱們有許多方法都要進行打印日誌,雖然咱們能夠每個方法裏面都寫上打印日誌,但這樣會顯得很麻煩,咱們只須要定義好一個打印日誌的方法,而後用修飾符調用裝飾咱們須要打印日誌的方法和類就能實現,咱們先從閉包開始理解python
閉包閉包
什麼是閉包,就是在方法裏面寫方法,而後內部方法能夠調用外部方法的變量,咱們先來看一個閉包的實現函數
def funA():學習
a = 1日誌
def inner():對象
print(a) #閉包內部能夠調用外面的參數io
return innerfunction
funa = funA()登錄
print(funa,funa.__name__) #打印結果,咱們會發現他是一個function(函數,或者能夠叫作方法),他的名字叫inner,__name__是內置參數,咱們能夠直接使用,既然是一個方法,咱們就能夠調用變量
funa() #打印結果:1 咱們經過變量名直接調用方法
裝飾器的定義
學習python咱們知道函數也是一個對象,若是是對象就能被調用,那麼咱們把方法當成參數放在另外一個方法中進行調用,咱們能夠經過方法調用方法
def funA(f):
f()
print('AAA')
def funB():
print('BBB')
funA(funB) #打印結果 BBB AAA
咱們會發現funB替換了f參數被調用了,若是咱們funB想要傳入參數怎麼辦,這時咱們就要用到上面的閉包了
def funA(f):
print('哈哈')
def inner(*args,**kwargs): #*args是經過元組的方式傳入,**kwargs是經過dict的方式傳入,
print('剛進入函數')
f(*args,**kwargs) #上面的閉包中咱們已經知道了能夠調用外面的變量
print('離開函數')
print('嘻嘻')
return inner
def funB(*args,**kwargs):
print(args,kwargs)
print('BBB')
funa = funA(funB) #打印結果:哈哈 嘻嘻 咱們在上面能夠看到返回的是一個方法,咱們用funa變量接收,這個就是inner函數
funa(1,2,3,name='tom',age=18) #打印結果:剛進入函數 (1,2,3) {'name':'tom','age':18} 離開函數 調用inner函數了把參數傳入
咱們的funcB會替換f(*args,**kwargs),咱們經過inner函數把參數傳入了funB中,這樣就實現了咱們的函數調用函數,咱們定義的其餘的方法也能夠在funA進行調用來實現咱們須要的效果,funA就是一個裝飾函數,在python中用了一個修飾符來代替咱們的執行過程,經過@就能實現裝飾器的使用,咱們須要把裝飾器定義在函數以前,若是裝飾器下面沒有函數就會報錯
@funA
def login(*args,**kwargs):
print('登錄成功')
咱們在這裏就已經實現了裝飾器的調用,他已經完成了裝飾器外層的打印 # 打印結果:哈哈 嘻嘻
login(name='tom',pwd='123') #(1,2,3) {'name':'tom','age':18}
這樣就定義好了裝飾器,咱們要注意的是這裏已經實現了變量名稱的一個轉換,調用過程咱們能夠看作是把inner()函數的變量名變成了login,login()函數的變量名已經變成了f,咱們只是把參數經過inner()傳入到了f()中,咱們能夠作一個判斷用戶是否存在的裝飾器
def has_user(func):
user = {'name':'tom','pwd':'123'}
def inner(*args,**kwargs):
name = kwargs['name']
pwd = kwargs['pwd']
if name == user['name'] and pwd == user['pwd']:
print('用戶存在')
func(*args,**kwargs)
else:
print('用戶不存在')
return inner
@has_user
def login(*args,**kwargs):
print('登陸成功了')
login(name='tom',pwd='123') #打印結果:用戶存在 登錄成功