【譯】Python裝飾方法漫談(一)

講在開始


一直對Python中Decorator這個(gè)理念理解的不是很透徹,搜羅學(xué)習(xí)資料的時(shí)候發(fā)現(xiàn)了stackoverflow上一個(gè)略長略長但講述清楚詳盡的答案。準(zhǔn)備利用最近的空閑時(shí)間翻譯出來整理一下,當(dāng)個(gè)搬運(yùn)工。原答案鏈接在這里。

上面是問題鏈接,這個(gè)鏈接直接跳到答案部分 ??

http://stackoverflow.com/a/1594484

原答案代碼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ǔ)詳盡的講解。

閱讀下一篇?

http://www.itdecent.cn/p/5f1149145c6d

哪里翻譯的不好不詳盡的請隨時(shí)指出。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 本文轉(zhuǎn)自http://mingxinglai.com/cn/2015/08/python-decorator/ [...
    Jlan閱讀 620評論 0 5
  • Python裝飾器的高級用法(翻譯) 原文地址https://www.codementor.io/python/t...
    城南道閱讀 4,870評論 1 22
  • 要點(diǎn): 函數(shù)式編程:注意不是“函數(shù)編程”,多了一個(gè)“式” 模塊:如何使用模塊 面向?qū)ο缶幊蹋好嫦驅(qū)ο蟮母拍?、屬性?..
    victorsungo閱讀 1,697評論 0 6
  • 本文為《爬著學(xué)Python》系列第四篇文章。從本篇開始,本專欄在順序更新的基礎(chǔ)上,會有不規(guī)則的更新。 在Pytho...
    SyPy閱讀 2,575評論 4 11
  • 我不想占有世間任何一樣?xùn)|西. 江山風(fēng)月,本無常主,閑者便是主人. 這是怎樣一種情懷?又怎樣可以做到這樣一種情懷? ...
    于安然閱讀 195評論 0 0

友情鏈接更多精彩內(nèi)容