此系列檔案:
1. 我終于弄懂了Python的裝飾器(一)
2. 我終于弄懂了Python的裝飾器(二)
3. 我終于弄懂了Python的裝飾器(三)
4. 我終于弄懂了Python的裝飾器(四)
一、裝飾器基礎(什么是裝飾器)
Python的函式是物件
要了解裝飾器,您必須首先了解函式是Python中的物件,這具有重要的聯系,
讓我們來看一個簡單的例子:
def shout(word="yes"):
return word.capitalize()+"!"
print(shout())
# 輸出 : 'Yes!'
# 作為一個物件,您可以像其他物件一樣將函式賦給變數
scream = shout
#注意我們不使用括號:我們沒有呼叫函式
#我們將函式“shout”放入變數“scream”,
#這意味著您可以從“scream”中呼叫“shout”:
print(scream())
# 輸出: 'Yes!'
#除此之外,這意味著您可以洗掉舊名稱'shout',該功能仍可從'scream'訪問
del shout
try:
print(shout())
except NameError as e:
print(e)
#輸出: "name 'shout' is not defined"
print(scream())
# 輸出: 'Yes!'
請記住這一點,我們將在不久后回頭再說,
Python函式的另一個有趣特性是可以在另一個函式中定義它們!
def talk():
# 您可以在“talk”中動態定義一個函式...
def whisper(word="yes"):
return word.lower()+"..."
# ...并且可以立馬使用它,
print(whisper())
#您每次呼叫“talk”,都會定義“whisper”,然后在“talk”中呼叫“whisper”,
talk()
# 輸出:
# "yes..."
# 但是"whisper"不存在"talk"定義以外的地方:
try:
print(whisper())
except NameError as e:
print(e)
#輸出 : "name 'whisper' is not defined"
函式參考
OK,應該還在看吧?現在開始有趣的部分...
您已經看到函式是物件,
因此,函式:
- 可以分配給變數
- 可以在另一個函式中定義
這意味著一個函式可以return另一個功能,
def getTalk(kind="shout"):
# 我們頂一個即時的函式
def shout(word="yes"):
return word.capitalize()+"!"
def whisper(word="yes") :
return word.lower()+"...";
# 然后我們回傳它
if kind == "shout":
#我們不使用“()”,所以我們沒有呼叫函式,我們正在回傳這個函式物件
return shout
else:
return whisper
#獲取函式并將其分配給變數: "talk"
talk = getTalk()
#您可以看到“talk”是一個函式物件:
print(talk)
#輸出 : <function shout at 0xb7ea817c>
#函式物件回傳的內容:
print(talk())
#輸出 : Yes!
#如果您感到困惑,甚至可以直接使用它:
print(getTalk("whisper")())
#outputs : yes...
還有更多的內容!
如果可以return一個函式,則可以將其中一個作為引數傳遞:
def doSomethingBefore(func):
print("I do something before then I call the function you gave me")
print(func())
doSomethingBefore(scream)
#輸出:
#I do something before then I call the function you gave me
#Yes!
好吧,您只具備了解裝飾器所需的所有資訊,
您會看到,裝飾器是“包裝器(wrappers)”,這意味著它們使您可以在裝飾函式之前和之后執行代碼,而無需修改函式本身的代碼內容,
手工進行裝飾
您將知道如何進行手動操作:
#裝飾器是講另外一個函式作為引數的函式
def my_shiny_new_decorator(a_function_to_decorate):
# 在內部,裝飾器動態定義一個函式:包裝器(wrappers),
# 此功能將被包裝在原始功能的外部,以便它可以在代碼之前和之后執行代碼,
def the_wrapper_around_the_original_function():
# 在呼叫原始函式之前,將要執行的代碼放在此處
print("Before the function runs")
#在此處呼叫函式(使用括號)
a_function_to_decorate()
# 在呼叫原始函式后,將要執行的代碼放在此處
print("After the function runs")
#至此,“a_function_to_decorate”從未執行過,
#我們回傳剛剛創建的包裝函式,
#包裝器包含函式和在代碼之前和之后執行的代碼,隨時可以使用!
return the_wrapper_around_the_original_function
#現在,假設您創建了函式,但是不想再修改的函式,
def a_stand_alone_function():
print("I am a stand alone function, don't you dare modify me")
a_stand_alone_function()
#輸出: I am a stand alone function, don't you dare modify me
#所以,您可以裝飾它以擴展其行為,
#只需將其傳遞給裝飾器,它將動態地包裝在
#您想要的任何代碼中,并為您回傳準備使用的新功能:
a_stand_alone_function_decorated = my_shiny_new_decorator(a_stand_alone_function)
a_stand_alone_function_decorated()
#輸出:
#Before the function runs
#I am a stand alone function, don't you dare modify me
#After the function runs
現在,您可能希望每次呼叫a_stand_alone_function時a_stand_alone_function_decorated都呼叫它,
這很簡單,只需a_stand_alone_function用以下方法回傳的函式覆寫my_shiny_new_decorator:
a_stand_alone_function = my_shiny_new_decorator(a_stand_alone_function)
a_stand_alone_function()
#輸出:
#Before the function runs
#I am a stand alone function, don't you dare modify me
#After the function runs
#這正是裝飾器的作業!
裝飾器神秘化
這里展示一下使用裝飾器的語法:
@my_shiny_new_decorator
def another_stand_alone_function():
print("Leave me alone")
another_stand_alone_function()
#輸出:
#Before the function runs
#Leave me alone
#After the function runs
是的,僅此而已,@decorator只是實作以下目的的捷徑:
another_stand_alone_function = my_shiny_new_decorator(another_stand_alone_function)
裝飾器只是裝飾器設計模式的pythonic變體,
Python中嵌入了幾種經典的設計模式來簡化開發(例如迭代器),
當然,您可以累加裝飾器:
def bread(func):
def wrapper():
print("</''''''\>")
func()
print("<\______/>")
return wrapper
def ingredients(func):
def wrapper():
print("#tomatoes#")
func()
print("~salad~")
return wrapper
def sandwich(food="--ham--"):
print(food)
sandwich()
#輸出: --ham--
sandwich = bread(ingredients(sandwich))
sandwich()
#輸出:
#</''''''\>
# #tomatoes#
# --ham--
# ~salad~
#<\______/>
使用Python裝飾器語法:
@bread
@ingredients
def sandwich(food="--ham--"):
print(food)
sandwich()
#outputs:
#</''''''\>
# #tomatoes#
# --ham--
# ~salad~
#<\______/>
您設定裝飾器事項的順序是很重要的,如::
@ingredients
@bread
def strange_sandwich(food="--ham--"):
print(food)
strange_sandwich()
#outputs:
##tomatoes#
#</''''''\>
# --ham--
#<\______/>
# ~salad~
本文首發于BigYoung小站
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/95150.html
標籤:Python
