python--裝飾器詳解
Python---裝飾器詳解
定義:
本質上是一個函數。作用是用來裝飾另一個函數(即被裝飾函數),給被裝飾函數添加功能。前提是不能改變被裝飾函數的源代碼和調用方式。這樣的一個函數稱之為裝飾器。
解析:
下面我們話不多說,直接用代碼說明。下面是一個函數。
1 def add(): 2 b=1+2 3 print(b
4
5 add()
程序輸出:
————————
3
————————
現在我要給這個函數增加一個解釋性的句子,如下,我們可以編寫一個裝飾器:
1 #原函數 2 def add(): 3 a=1+2 4 print(a) 5 #裝飾器 6 def decorator(func): 7 def warpper(): 8 print("1+2的結果是:") 9 func() 10 return warpper 11 #註意此句 12 add=decorator(add) 13 #調用函數 14 add()
程序輸出:
——————————
1+2的結果是:
3
——————————
這樣我們就成功的達成了我們的目的。這裏要註意第12行的這一句,這一句是將add這個函數對象傳入了decorator()函數,返回的是一個新函數變量,這個新函數對象又重新賦值給add,這樣就可以保證不改變被裝飾函數的調用方式不變。在Python語法中有一種更優雅的方式可以代替第十二行的語句。如下:
1 #裝飾器 2 def decorator(func): 3 def warpper(): 4 print("1+2的結果是:") 5 func() 6 return warpper 7 8 #add=decorator(add) 9 #原函數 10 @decorator#[email protected] 11 def add(): 12 a=1+2 13 print(a) 14 #調用函數 15 add()
[email protected](xxx為裝飾器函數名)即可
被裝飾函數有參數怎麽辦?
如果被裝飾器函數有參數呢?該怎們班?不用擔心,我們可以用不定參數的形式來收集參數。實例代碼如下:
1 def decorator(func): 2 def warpper(*args,**kwargs): 3 print("相加的結果是:") 4 func(*args,**kwargs) 5 return warpper 6 7 @decorator 8 def add(x,y): 9 a=x+y 10 print(a) 11 12 add(2,3)
程序輸出:
——————————————————
相加的結果是:
5
——————————————————
如上,我們給包裝函數加上接收參數,然後傳給func()函數就行了。這樣不管被裝飾函數有怎樣的參數都不怕了。
下面寫一個頁面驗證的裝飾器。
大家知道有些網站的一部分頁面是要求用戶登錄之後才可以訪問的,比如下面的三個函數(分別代表三個頁面):
1 def index(): 2 print("welcome to the index page") 3 def home(): 4 print("welcome to the home page") 5 def bbs(): 6 print("welcome to the bbs page") 7 return "I am the return contents"
假如說現在我們要給home頁面和bbs頁面加上驗證,顯然現在更改源代碼是不可行的。這個時候我們可以用裝飾器,如下:
1 username,passwd="jack","abc123"#模擬一個已登錄用戶 2 def decorator(func): 3 def warpper(*args,**kwargs): 4 Username=input("Username:").strip() 5 password=input("Password:").strip() 6 if username==Username and passwd==password: 7 print("Authenticate Success!") 8 func(*args,**kwargs) 9 else: 10 exit("Username or password is invalid!") 11 return warpper 12 13 def index(): 14 print("welcome to the index page") 15 @decorator 16 def home(): 17 print("welcome to the home page") 18 @decorator 19 def bbs(): 20 print("welcome to the bbs page") 21 return "I am the return contents" 22 23 index() 24 home() 25 bbs()
程序結果:
————————
welcome to the index page #index頁面未驗證直接可以登入
Username:jack
Password:abc123
Authenticate Success! #登錄的而情形
welcome to the home page
Username:jack #密碼或用戶名錯誤的情形
Password:123
Username or password is invalid!
————————
我們註意到bbs()是有返回值的,如果我們把上述代碼的最後一句(第25行)改為“print(bbs())”之後再看看他的輸出結果:
————————
welcome to the index page
Username:jack
Password:abc123
Authenticate Success!
welcome to the home page
Username:jack
Password:abc123
Authenticate Success!
welcome to the bbs page
None #返回值能麽成None了???
————————
What happened! bbs()的返回值打印出來竟然是None。怎麽會這樣?這樣的話不就改變了被裝飾函數的源代碼了嗎?怎樣才能解決呢?
我們來分析一下:
我們執行bbs函數其實就相當於執行了裝飾器裏的wrapper函數,仔細分析裝飾器發現wrapper函數卻沒有返回值,所以為了讓他可以正確保證被裝飾函數的返回值可以正確返回,那麽需要對裝飾器進行修改:
1 username,passwd="jack","abc123"#模擬一個已登錄用戶 2 def decorator(func): 3 def warpper(*args,**kwargs): 4 Username=input("Username:").strip() 5 password=input("Password:").strip() 6 if username==Username and passwd==password: 7 print("Authenticate Success!") 8 return func(*args,**kwargs)#在這裏加一個return就行了 9 else: 10 exit("Username or password is invalid!") 11 return warpper 12 13 def index(): 14 print("welcome to the index page") 15 @decorator 16 def home(): 17 print("welcome to the home page") 18 @decorator 19 def bbs(): 20 print("welcome to the bbs page") 21 return "I am the return contents" 22 23 index() 24 home() 25 bbs()
如圖加上第8行的return就可以解決了。下面我們在看看改後的程序輸出:
————————
welcome to the index page
Username:jack
Password:abc123
Authenticate Success!
welcome to the home page
Username:jack
Password:abc123
Authenticate Success!
welcome to the bbs page
I am the return contents #bbs()的返回值得到了正確的返回
——-——————
好了,返回值的問題解決了.
既然裝飾器是一個函數,那裝飾器可以有參數嗎?
答案是肯定的。我們同樣可以給裝飾器加上參數。比如還是上面的三個頁面函數作為例子,我們可以根據不同頁面的驗證方式來給程序不同的驗證,而這個驗證方式可以以裝飾器的參數傳入,這樣我們就得在裝飾器上在嵌套一層函數 了:
1 username,passwd="jack","abc123"#模擬一個已登錄用戶 2 def decorator(auth_type): 3 def out_warpper(func): 4 def warpper(*args,**kwargs): 5 Username=input("Username:").strip() 6 password=input("Password:").strip() 7 if auth_type=="local": 8 if username==Username and passwd==password: 9 print("Authenticate Success!") 10 return func(*args,**kwargs) 11 else: 12 exit("Username or password is invalid!") 13 elif auth_type=="unlocal": 14 print("HERE IS UNLOCAL AUTHENTICATE WAYS") 15 return warpper 16 return out_warpper 17 18 def index(): 19 print("welcome to the index page") 20 @decorator(auth_type="local") 21 def home(): 22 print("welcome to the home page") 23 @decorator(auth_type="unlocal") 24 def bbs(): 25 print("welcome to the bbs page") 26 return "I am the return contents" 27 28 index() 29 home() 30 bbs()
輸出:
————————
welcome to the index page
Username:jack
Password:abc123
Authenticate Success!
welcome to the home page
Username:jack
Password:abc123
HERE IS UNLOCAL AUTHENTICATE WAYS
————————
可見,程序分別加入了第2行和第16行和中間的根據auth_type參數的判斷的相關內容後, 就解決上述問題了。對於上面的這一個三層嵌套的相關邏輯,大家可以在 pycharm裏頭加上斷點,逐步調試,便可發現其中的道理。
總結
要想學好叠代器就必須理解一下三條:
1.函數即變量(即函數對象的概念)
2.函數嵌套
3.函數式編程
作者:彭前超(QQ:3480487308)
時間:2017/6/10 23:09
轉載請註明出處,謝謝合作。本人另有Python視頻教程,想要的qq聯系,非誠勿擾.
python--裝飾器詳解