Python有大量強大又貼心的特性,如果要列個最受歡迎排行榜,那么裝飾器絕對會在其中。
初識裝飾器,會感覺到優雅且神奇,想親手實現時卻總有距離感,就像深閨的冰美人一般。這往往是因為理解裝飾器時把其他的一些概念混雜在一起了。待我撫去層層面紗,你會看到純粹的裝飾器其實蠻簡單直率的。
裝飾器的原理
在解釋器下跑個裝飾器的例子,直觀地感受一下。
# make_bold就是裝飾器,實現方式這里略去
>>> @make_bold... def get_content():... return 'hello world'...>>> get_content()'<b>hello world</b>'
被 make_bold 裝飾的 get_content ,調用后返回結果會自動被 b 標簽包住。怎么做到的呢,簡單4步就能明白了。
1. 函數是對象
我們定義個 get_content 函數。這時 get_content 也是個對象,它能做所有對象的操作。 
def get_content(): return 'hello world'
它有 id ,有 type ,有值。 
>>> id(get_content)140090200473112>>> type(get_content)<class 'function'>>>> get_content<function get_content at 0x7f694aa2be18>
跟其他對象一樣可以被賦值給其它變量。
>>> func_name = get_content>>> func_name()'hello world'
它可以當參數傳遞,也可以當返回值
>>> def foo(bar):... print(bar())... return bar...>>> func = foo(get_content)hello world>>> func()'hello world'
2. 自定義函數對象
我們可以用 class 來構造函數對象。有成員函數 __call__ 的就是函數對象了,函數對象被調用時正是調用的 __call__ 。 
class FuncObj(object):  def __init__(self, name):    print('Initialize')    self.name= name  def __call__(self):    print('Hi', self.name)我們來調用看看。可以看到, 函數對象的使用分兩步:構造和調用 (同學們注意了,這是考點)。 
>>> fo = FuncObj('python')Initialize>>> fo()Hi python3. @ 是個語法糖
裝飾器的 @ 沒有做什么特別的事,不用它也可以實現一樣的功能,只不過需要更多的代碼。 
@make_bolddef get_content(): return 'hello world'# 上面的代碼等價于下面的def get_content(): return 'hello world'get_content = make_bold(get_content)
make_bold 是個函數,要求入參是函數對象,返回值是函數對象。 @ 的語法糖其實是省去了上面最后一行代碼,使可讀性更好。用了裝飾器后,每次調用 get_content ,真正調用的是 make_bold 返回的函數對象。
新聞熱點
疑難解答