定義:
本質上是一個函數。作用是用來裝飾另一個函數(即被裝飾函數),給被裝飾函數添加功能。前提是不能改變被裝飾函數的源代碼和調用方式。這樣的一個函數稱之為裝飾器。
解析:
下面我們話不多說,直接用代碼說明。下面是一個函數。
1 def add():
2 b=1+2
3 print(b)
4
5 add()
程序輸出:
————————
3
————————
- 現在我要給這個函數增加一個解釋性的句子,如下,我們可以編寫一個裝飾器:
#原函數
def add():
a=1+2
print(a)
#裝飾器
def decorator(func):
def warpper():
print("1+2的結果是:")
func()
return warpper
#注意此句
add=decorator(add)
#調用函數
add()
程序輸出:
——————————
1+2的結果是:
3
——————————
- 這樣我們就成功的達成了我們的目的。這里要注意第12行的這一句,這一句是將add這個函數對象傳入了decorator()函數,返回的是一個新函數變量,這個新函數對象又重新賦值給add,這樣就可以保證不改變被裝飾函數的調用方式不變。在Python語法中有一種更優雅的方式可以代替第十二行的語句。如下:
#裝飾器
def decorator(func):
def warpper():
print("1+2的結果是:")
func()
return warpper
#add=decorator(add)
#原函數
@decorator#換成@符號
def add():
a=1+2
print(a)
#調用函數
add()
在被裝飾函數前面直接加上“@xxx”(xxx為裝飾器函數名)即可
被裝飾函數有參數怎么辦?
- 如果被裝飾器函數有參數呢?該怎們班?不用擔心,我們可以用不定參數的形式來收集參數。實例代碼如下:
def decorator(func):
def warpper(*args,**kwargs):
print("相加的結果是:")
func(*args,**kwargs)
return warpper
@decorator
def add(x,y):
a=x+y
print(a)
add(2,3)
程序輸出:
——————————————————
相加的結果是:
5
——————————————————
如上,我們給包裝函數加上接收參數,然后傳給func()函數就行了。這樣不管被裝飾函數有怎樣的參數都不怕了。
下面寫一個頁面驗證的裝飾器。
- 大家知道有些網站的一部分頁面是要求用戶登錄之后才可以訪問的,比如下面的三個函數(分別代表三個頁面):
def index():
print("welcome to the index page")
def home():
print("welcome to the home page")
def bbs():
print("welcome to the bbs page")
return "I am the return contents"
- 假如說現在我們要給home頁面和bbs頁面加上驗證,顯然現在更改源代碼是不可行的。這個時候我們可以用裝飾器,如下:
username,passwd="jack","abc123"#模擬一個已登錄用戶
def decorator(func):
def warpper(*args,**kwargs):
Username=input("Username:").strip()
password=input("Password:").strip()
if username==Username and passwd==password:
print("Authenticate Success!")
func(*args,**kwargs)
else:
exit("Username or password is invalid!")
return warpper
def index():
print("welcome to the index page")
@decorator
def home():
print("welcome to the home page")
@decorator
def bbs():
print("welcome to the bbs page")
return "I am the return contents"
index()
home()
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函數卻沒有返回值,所以為了讓他可以正確保證被裝飾函數的返回值可以正確返回,那么需要對裝飾器進行修改:
username,passwd="jack","abc123"#模擬一個已登錄用戶
def decorator(func):
def warpper(*args,**kwargs):
Username=input("Username:").strip()
password=input("Password:").strip()
if username==Username and passwd==password:
print("Authenticate Success!")
return func(*args,**kwargs)#在這里加一個return就行了
else:
exit("Username or password is invalid!")
return warpper
def index():
print("welcome to the index page")
@decorator
def home():
print("welcome to the home page")
@decorator
def bbs():
print("welcome to the bbs page")
return "I am the return contents"
index()
home()
bbs()
- 如圖加上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()的返回值得到了正確的返回
——-——————
好了,返回值的問題解決了.
既然裝飾器是一個函數,那裝飾器可以有參數嗎?
- 答案是肯定的。我們同樣可以給裝飾器加上參數。比如還是上面的三個頁面函數作為例子,我們可以根據不同頁面的驗證方式來給程序不同的驗證,而這個驗證方式可以以裝飾器的參數傳入,這樣我們就得在裝飾器上在嵌套一層函數 了:
username,passwd="jack","abc123"#模擬一個已登錄用戶
def decorator(auth_type):
def out_warpper(func):
def warpper(*args,**kwargs):
Username=input("Username:").strip()
password=input("Password:").strip()
if auth_type=="local":
if username==Username and passwd==password:
print("Authenticate Success!")
return func(*args,**kwargs)
else:
exit("Username or password is invalid!")
elif auth_type=="unlocal":
print("HERE IS UNLOCAL AUTHENTICATE WAYS")
return warpper
return out_warpper
def index():
print("welcome to the index page")
@decorator(auth_type="local")
def home():
print("welcome to the home page")
@decorator(auth_type="unlocal")
def bbs():
print("welcome to the bbs page")
return "I am the return contents"
index()
home()
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.函數式編程