原文查看:
http://www.ibaiyang.org/2013/01/04/python-decorator-introduction/
本文章的代碼沒有高亮,請查看原文,格式比較好。
本篇文章將介紹python中的decorator,中文翻譯為 裝飾器 魔法。在這篇文章中我們將熟悉decorator使用的基本方式和基本使用例子,並利用decorator來實現一個進階的例子—緩衝系統(cache system)。
Decorator已某種方式可以簡化編碼量,並增加了代碼的可讀性,這也是為何python中引入了 裝飾器 魔法。我們可以看看如下例子:
def foo(self):passfoo = classmethod(foo)
可以看出以上的代碼結構讓人看起來不舒服,如果使用了裝飾器,那麼一切將變得美好。
@classmethoddef foo(self):pass
在python中,裝飾器(decorator)是用於修改函數,類方法的python對象。裝飾器可以分為函數,類裝飾器,對裝飾器唯一的限制是其可調用性(callable),我們知道,函數本身是可調用的,所以如果使用類裝飾器,我們就必須實作類別的__call__方法。
裝飾器必須用在合適的地方,否則並不能得到很好的效果,比如我們要用裝飾器實現以下的功能:
def value():return"hello world!"
使其輸出結果為
<h1><li>hello world!</li></h1>
那麼我們可以建立如下的裝飾器:
def li(func):return"<li>"+ func()+"</li>"def h1(func):return"<h1>"+ func()+"</h1>"
然後這樣調用即可
@h1@lidef value():return"hello world!"print value()
即增加了代碼的可讀性,又提高代碼的可重用性。
看過一些簡單的使用方法後,我們可以用數學語言來描述裝飾器。
@f1(arg)@f2def func():pass
等價於
def func():passfunc = f1(arg)(f2(func))
當初我也在接觸到裝飾器一些簡單的使用方式後,並不對裝飾器高度興趣,因為我們畢竟可以用其他的方式實現其功能,但是後面無意中接觸到了用裝飾器做cache系統,讓我突然覺得有裝飾器的好處和妙處。
假如,我們有一個如下遞迴,用來實現Fibonacci_number遞迴
def fib(n):if n <2:return1return fib(n-1)+ fib(n-2)
這個遞迴有什麼問題呢,我們知道遞迴在通常情況下,會產生許多相同的子調用,因此我們需要一個緩衝來儲存中間結果,可以加速遞迴過程。
我們來對比一下使用cache系統之後的前後遞迴調用過程,以fib(5)為例:
可以發現重複調用子過程的現象消失,我還用profile對比了一下時間,後者快了許多,特別是當fib參數越大的時候,那我們如何?這個cache系統,下面給出一個簡單的版本:
from functools import wrapsdef cache(func): caches ={}@wraps(func)def wrap(*args):if args notin caches: caches[args]= func(*args)return caches[args]return wrap
使用方法非常簡單
@cachedef fib(n):if n <2:return1return fib(n-1)+ fib(n-2)print fib(5)#call fib so easy!
從上面我們看出,我們在沒有任何代碼修改的前提下實現了一個簡單的cache系統,記住沒有修改任何代碼的前提下,還有就是並不是所有的遞迴都適合此類方法,比如二叉樹就沒有必要,當且只有重複的子程序呼叫時採用此方法才有實際意義,反之,畫蛇添足。
Reference:
- http://code.activestate.com/recipes/577479-simple-caching-decorator/
- http://simeonfranklin.com/blog/2012/jul/1/python-decorators-in-12-steps/
-----------------打造高品質的文章 更多關注 把酒泯恩仇---------------
為了打造高品質的文章,請 推薦 一下吧。。。。謝謝了,請關注我後續的文章,會更精彩哦
請關注sina微博:http://weibo.com/baiyang26
把酒泯恩仇官方部落格:http://www.ibaiyang.org 【推薦用google reader訂閱】
把酒泯恩仇官方豆瓣:http://www.douban.com/people/baiyang26/
如果您想轉載本部落格,請註明出處
如果您對本文有意見或者建議,歡迎留言