講在開始
一直對Python中Decorator這個(gè)理念理解的不是很透徹,搜羅學(xué)習(xí)資料的時(shí)候發(fā)現(xiàn)了stackoverflow上一個(gè)略長略長但講述清楚詳盡的答案。準(zhǔn)備利用最近的空閑時(shí)間翻譯出來整理一下,當(dāng)個(gè)搬運(yùn)工。原答案鏈接在這里。
上面是問題鏈接,這個(gè)鏈接直接跳到答案部分 ??
原答案代碼在2.7版本下可以全部運(yùn)行成功,我將其中的代碼用3.5版本重寫,并改正了一些沒有遵循PEP8規(guī)范的代碼,以便自己學(xué)習(xí)理解的更深入一些
Kulbear:因?yàn)榇髮W(xué)在國外上的,整個(gè)CS的教育背景基本是全英文,有些詞翻譯的可能不是很專業(yè)?,F(xiàn)在還記得當(dāng)初大一時(shí)候看書不知assignment statement是賦值語句。如果有翻譯的錯誤,請隨時(shí)指出。
基礎(chǔ)
一切函數(shù)(Function)皆為對象(Object)
作為理解裝飾器(Decorator)的重要前提,首先你要明白:Python中所有的函數(shù)都是對象
讓我們來看一個(gè)簡單的例子:
# -*- coding: utf-8 -*-
def shout(word="yes"):
return word.capitalize() + "!"
print(shout())
# 輸出 : Yes!
# 既然一切函數(shù)都是對象,那么你可以像賦值其他對象到一個(gè)變量一樣,
# 將函數(shù)賦值給變量,如下
scream = shout
# 需要注意的是,我們沒有在函數(shù)后面加上():我們并不是在調(diào)用這個(gè)函數(shù),
# 而是在將函數(shù)shout“放入”變量scream中。
# 這意味著你可以通過scream來調(diào)用shout函數(shù),如下
print(scream())
# 輸出 : Yes!
# 此外,即使現(xiàn)在你刪除了shout,你仍然可以通過scream調(diào)用這個(gè)函數(shù)
del shout
try:
print(shout())
except NamError as e:
print(e)
# 輸出 : name 'shout' is not defined
print(scream())
# 輸出 : Yes!
好,牢記這一點(diǎn),我們稍后還會回顧。
另一個(gè)你需要知道的特性是:在Python里,函數(shù)可以定義在另一個(gè)函數(shù)里
# -*- coding: utf-8 -*-
def talk():
# 現(xiàn)在讓我們在這里定義一個(gè)whisper函數(shù) ...
def whisper(word="yes"):
return word.lower() + "..."
# 直接調(diào)用whisper函數(shù)
print(whisper())
# 你**每次**調(diào)用talk函數(shù)的時(shí)候,whisper函數(shù)都會被重新定義
# 并隨后在talk內(nèi)部被調(diào)用
talk()
# 輸出 : yes...
# 但很明顯,whisper函數(shù)在talk函數(shù)之外是undefined的
try:
print(whisper())
except NameError as e:
print(e)
# 輸出 : name 'whisper' is not defined
# 牢記,Python中函數(shù)皆為對象
函數(shù)引用(Function Reference)
很高興你持續(xù)讀到了這里,有趣的才剛剛開始(講道理,這句話我覺得很老外的語氣...)
你已經(jīng)明白了函數(shù)皆為對象這點(diǎn),因此我們可以總結(jié)出,對于一個(gè)函數(shù),它:
- 可以被賦給變量
- 可以再另一個(gè)函數(shù)中被定義
因此,一個(gè)函數(shù)可以返回(return)另一個(gè)函數(shù)
# -*- coding: utf-8 -*-
def scream(word="yes"):
# 在原答案中沒有這個(gè)函數(shù),應(yīng)該是來源于上面的代碼片段
# 這里我添加上以便每個(gè)文件可以獨(dú)立執(zhí)行
return word.capitalize() + "!"
def get_talk(kind="shout"):
def shout(word="yes"):
return word.capitalize() + "!"
def whisper(word="yes"):
return word.lower() + "..."
if kind == "shout":
# 由于我們要返回的是函數(shù)這個(gè)對象,所以不使用(),
return shout
else:
return whisper
# 如何使用?
# 獲取一個(gè)函數(shù),并把他復(fù)制給變量talk
talk = get_talk()
print(talk)
# 輸出 : <function shout at 0xb7ea817c>
print(talk())
# 輸出 : Yes!
# 也可以直接調(diào)用
print(get_talk("whisper")())
# 輸出 : yes...
def do_something_before(func):
print("I do something before then I call the function you gave me")
print(func())
do_something_before(scream)
# 輸出:
# I do something before then I call the function you gave me
# Yes!
好了,萬事俱備,只欠東風(fēng)了,理解裝飾器所需要的知識點(diǎn)你應(yīng)該已經(jīng)全部具備了。
You see, decorators are “wrappers”, which means that they let you execute code before and after the function they decorate without modifying the function itself.
動手寫一個(gè)裝飾器吧
簡單來說,裝飾器就是一個(gè)接受其他函數(shù)為參數(shù)的函數(shù)
def my_shiny_new_decorator(a_function_to_decorate):
# 這個(gè)函數(shù)“包裝”了上面?zhèn)魅氲暮瘮?shù),并且在被包裝的函數(shù)前后
# 當(dāng)前函數(shù)可以添加執(zhí)行一些別的代碼
def the_wrapper_around_the_original_function():
# 被包裝的函數(shù)之前要執(zhí)行的代碼部分
print("Before the function runs")
# 調(diào)用傳入的函數(shù)a_function_to_decorate
# 因?yàn)槭钦{(diào)用,所以要帶有()
a_function_to_decorate()
# 被包裝的函數(shù)之后要執(zhí)行的代碼部分
print("After the function runs")
# 此時(shí), "a_function_to_decorate" 從未被執(zhí)行過.
# 我們返回“包裝”用的這個(gè)函數(shù) "the_wrapper_around_the_original_function"
return the_wrapper_around_the_original_function
# 現(xiàn)在,創(chuàng)建一個(gè)之后不做更改的函數(shù)
def a_stand_alone_function():
print("I am a stand alone function")
a_stand_alone_function()
# 輸出 : I am a stand alone function
# 現(xiàn)在,你可以通過裝飾器來擴(kuò)展上面這個(gè)函數(shù)
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
# After the function runs
# 或者
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
# After the function runs
很Pythonic的調(diào)用方法
@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
后記
And guess what? That’s EXACTLY what decorators do!
這只是原答案的基礎(chǔ)部分,做出了十分基礎(chǔ)詳盡的講解。
閱讀下一篇?
哪里翻譯的不好不詳盡的請隨時(shí)指出。