def func1(): print "inside func1()" def func2(): print "inside func2()"
我們希望在呼叫 func1() 前顯示 Entering func1, 而在離開 func1() 後顯示 Exited func1, 對 func2() 的要求也是相同,只是把函式名字換成 func2, 最直接的方法是修改 func1 及 func2 的實作內容, 可是這樣做實在太累贅了, 有沒有辦法把 func1 跟 func2 當作物件, 自己寫一個額外的函式來「裝飾」這些物件? Python 語言中所提供的 decorator 語法可以幫我們達到這個目的 (decorator 就是裝飾者的意思)。 decorator 的使用語法如下
@myDecorator def func1(): print "inside func1()" @myDecorator def func2(): print "inside func2()"
亦即在函式定義的前一行加上 @myDecorator
,
myDecorator
是一個我們即將實作的類別或是函式的名字,
實作的內容決定如何裝飾 func1 及 func2。實作內容如下
class myDecorator(object): def __init__(self, f): self.f = f def __call__(self): print "Entering", self.f.__name__ self.f() print "Exited", self.f.__name__
myDecorator 實際上就是把函式當作輸入, 而傳回值一定要是一個可呼叫的物件, 所以一定要定義 __call__ 這個函式, 如何裝飾輸入函式就是在 __call__ 中的實作完成。
熟悉 Python 的人會說,沒有 decorator 語法一樣可以完成相同的要求,
如 func1 = modifyFunc(func1)
亦即定義一個以函式為輸入的函式 modifyFunc,
把 modifyFunc 裝飾過後的結果 (必須是函式) 當做傳回值指定給原先輸入的函式。
可是有了 decorator 語法,就不需要指定的動作,
只需要在函式的定義前一行加上 @myDecorator
。
其實 @
只是一個便利的語法 (syntax sugar) 而已,
其作用是將一個函式 func1 當作另一個函式 myDecorator 的輸入,
並將 myDecorator 傳回值指定給原先的函式 func1。decorator 之所以有
那麼多的應用
是因為這個便利的語法改變了我們對程式設計的看法。
藉由成為程式語言的一項語法,decorator 將函式當做輸入物件的想法
變為主流的思考方式。
此外,decorator 還可以串起來 (chained decorator),比如
@decorator1 @decorator2 def myfunc(): pass上面的程式碼等價於
myfunc = decorator1(decorator2(myfunc))其實 decorator 可以擁有參數,例如
@decorator(arg1) def myfunc(arg2): pass
想要了解具有參數的 decorator 可以參考 Python Decorators II: Decorator Arguments 。 之後,我會介紹幾個關於 decorator 應用的例子。
No comments:
Post a Comment