python decorator 進階
阿新 • • 發佈:2017-07-20
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-inobjects, 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(*)也是合理的,我們來看看修改後的代碼classcost_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 進階