1. 程式人生 > >python decorator 進階

python decorator 進階

ng- -a gin __call__ complex 產生 sel sin tac

轉自:http://www.cnblogs.com/xybaby/p/6274283.html

上一篇文章開始的時候提到

 “一般來說,裝飾器是一個函數,接受一個函數(或者類)作為參數,返回值也是也是一個函數(或者參數)”

有一般情況,就有特殊情況。第一種特殊情況:裝飾器可能也是一個類;第二種特殊情況:裝飾器返回的對象的類型不一定等同於被裝飾對象的類型。

  對於第一種情況,我們知道對於任何callable的對象都可以進行調用(在對象名稱後面使用小括號),callable對象的範圍就比較廣了
(user-defined functions, built-in functions, methods of built-in
objects, class objects, methods of class instances, and certain class instances themselves are callable; extensions may define additional callable object types).

函數(方法)和類是callable,這個是很好理解的,如果一個類定義了__call__方法,那麽該類的實例也是callable。另外,

@dec def func():pass   等價於: func = dec(func),所以如果dec是一個類,那麽dec(func)是合理的,而被裝飾後的func就變成了dec類的一個實例,如果dec類定義了__call__, 那麽調用func(*)也是合理的,我們來看看修改後的代碼
class
cost_time_logger(object): def __init__(self, func): self.func = func def __call__(self, *args, **kwargs): import time begin = time.time() try: return self.func(*args, **kwargs) finally: print(func %s cost %s % (self.func.__name__, time.time() - begin)) @cost_time_logger def complex_func(num): ret
= 0 for i in xrange(num): ret += i * i return ret if __name__ == __main__: print complex_func(100000)

功能和上一篇文章的code snippet 0是一樣的,但是type(complex_func) 變成了 <class ‘__main__.cost_time_logger‘>,這也說明了第二種情況:被裝飾的對象原本是函數,被裝飾之後變成了一個類實例。

  在pep-0318中,例舉了一個用裝飾器實現單例的例子,代碼如下
def singleton(cls):
    instances = {}
    def getinstance():
        if cls not in instances:
            instances[cls] = cls()
        return instances[cls]
    return getinstance
 
@singleton
class MyClass:
    pass
 
if __name__ == __main__:
    print type(MyClass)

MyClass被裝飾前是一個類,被裝飾後變成了一個function。   筆者不是很喜歡這種改變被裝飾對象的類型的實現方法,這種實現對代碼的閱讀者不是很友好,而且可能產生一些莫名其妙的BUG,浪費debug的時間。對於單例的例子,stackoverflow上也有其他的實現。 references: pep-0318:https://www.python.org/dev/peps/pep-0318/#syntax-alternatives Creating a singleton in Python:http://stackoverflow.com/questions/6760685/creating-a-singleton-in-python

python decorator 進階