理解python中的裝飾器

wklken發表於2015-12-14

python的函式是物件

要理解裝飾器,首先,你必須明白,在python中,函式是物件. 這很重要.

簡單例子來理解為什麼

好了,記住這點,我們將會很快用到它.

Python函式另一個有趣的特性是,函式可以被定義在另一個函式裡面

函式引用

好了,到這裡了,接下來是有意思的部分,我們剛才看到 函式是物件,然後:

1.函式可以賦值給一個變數

2.函式可以定義在另一個函式內部

即,這也意味著一個函式可以返回另一個函式:-),讓我們來看另一段程式碼

但是稍等,如果你可以返回一個函式,那麼你也可以將函式作為引數傳遞

好了,現在你已經瞭解要理解裝飾器的每件事.

裝飾器就是封裝器,可以讓你在被裝飾函式之前或之後執行程式碼,而不必修改函式本身

手工裝飾器

如何書寫一個裝飾器

到這裡,或許你想每次呼叫a_stand_alone_function都使用a_stand_alone_function_decorated替代之
很簡單,只需要將a_stand_alone_function用my_shiny_new_decorator裝飾返回

裝飾器闡述

前面的例子,使用裝飾器語法

是的,就是這麼簡單. @decorator是下面程式碼的簡寫

裝飾器只是 裝飾器模式的python實現

python程式碼中還存在其他幾個經典的設計模式,以方便開發,例如迭代器iterators

當然,你可以累加裝飾器

使用python裝飾器語法

裝飾器位置的順序很重要

最後回答問題

好了,到這裡你可以高興地離開了,或者來看下一些裝飾器高階的用法

向裝飾器函式傳遞引數

裝飾方法

Python中物件的方法和函式是一樣的,除了物件的方法首個引數是指向當前物件的引用(self)。這意味著你可以用同樣的方法構建一個裝飾器,只是必須考慮self

當然,你可以構造一個更加通用的裝飾器,可以作用在任何函式或物件方法上,而不必關係其引數
使用

如下程式碼

向裝飾器傳遞引數

好了,現在你或許會想是否可以向裝飾器本身傳遞引數

裝飾器必須使用函式作為引數,所以這看起來會有些複雜,你不能直接傳遞引數給裝飾器本身

在開始處理這個問題前,看一點提醒

上面兩個形式本質上是相同的, “my_decorator” 被呼叫.所以當你使用”@my_decorator”,告訴python一個函式被變數”my_decorator”標記
這十分重要,因為你提供的標籤直接指向裝飾器…或者不是,繼續

我們跳過中間變數,做同樣的事情

使用裝飾器語法,更簡短

到這裡,我們使用@呼叫一個函式

回到問題,向裝飾器本身傳遞引數,如果我們可以通過函式去建立裝飾器,那麼我們可以傳遞引數給這個函式,對麼?

好了,that’s it.引數可以設定為變數

你可以看到,你可以使用像其它函式一樣使用這個方法向裝飾器傳遞引數.如果你願意你甚至可以使用 arg *kwargs.

但是記住,裝飾器僅在Python程式碼匯入時被呼叫一次,之後你不能動態地改變引數.當你使用”import x”,函式已經被裝飾,所以你不能改變什麼

練習:一個裝飾裝飾器的裝飾器

作為獎勵,我將展示建立可以處理任何引數的裝飾器程式碼片段. 畢竟,為了接收引數,必須使用另一個函式來建立裝飾器

讓我們來給裝飾器寫一個裝飾器:

使用:

我知道,到現在你一定會有這種感覺,就像你聽一個人說“在理解遞迴之前,你必須首先了解遞迴”,但是現在,掌握這兒你有沒有覺得很棒?

裝飾器使用最佳實踐

  • 這是Python2.4的新特性,所以確保你的程式碼在2.4及之上的版本執行
  • 裝飾器降低了函式呼叫的效能,記住這點
  • You can not un-decorate a function. There are hacks to create decorators that can be removed but nobody uses them. So once a function is decorated, it’s done. For all the code.
  • 裝飾器包裝函式,所以很難debug

Python2.5解決了最後一個問題,它提供functools模組,包含functools.wraps.這個函式會將被裝飾函式的名稱,模組,文件字串拷貝給封裝函式,有趣的是,functools.wraps是一個裝飾器:-)

裝飾器為何那麼有用

現在的問題是,我們用裝飾器來坐什麼?看起來很酷很強大,但是如果有實踐的例子會更好.好了,有1000種可能。經典的用法是,在函式的外部,擴充套件一個函式的行為(你不需要改變這個函式),或者,為了除錯的目的(我們不修改的原因是這是臨時的),你可以使用裝飾器擴充套件一些函式,而不用在這些函式中書寫相同的函式實現一樣的功能

DRY原則,例子:

裝飾器意味著,你可以用正確的方法實現幾乎所有的事情,而不必重寫他們

Python本身提供了一些裝飾器:property,staticmethod,等等,

Django使用裝飾器去管理快取和許可權. Twisted to fake inlining asynchronous functions calls.用途廣泛

EDIT: 鑑於這個回答的完美,人們希望我去回答metaclass,我這樣做了

打賞支援我寫出更多好文章,謝謝!

打賞作者

打賞支援我寫出更多好文章,謝謝!

任選一種支付方式

理解python中的裝飾器 理解python中的裝飾器

相關文章