1. 概述
裝飾器是一個很著名的設計模式,經常被用于有切面需求的場景,較為經典的有插入日志、性能測試、事務處理等。裝飾器是解決這類問題的絕佳設計,有了裝飾器,我們就可以抽離出大量函數中與函數功能本身無關的雷同代碼并繼續重用。概括的講,裝飾器的作用就是為已經存在的對象添加額外的功能。
Python從語法層為我們提供了非常好的實現裝飾模式的方法。
2. 動機
如果不使用python
裝飾器語法的話,我們如果想轉換一個函數(或換句話說,給函數加上裝飾器,例如將一個普通函數轉變成類函數)的話,代碼看起來是這樣子的:
'''
Created on 2011-12-14
@author: Ahan
'''
class Foo(object):
def foo(self):
print("foo is called")
pass
#Turn the method foo to a class method
foo = classmethod(foo)
if __name__ == '__main__':
Foo.foo()
pass
可以想象,函數一多,代碼的可讀性就大大下降了。Python
提供了一個另一種優雅的方法來解決這個問題。修改后的代碼如下:
'''
Created on 2011-12-14
@author: Ahan
'''
class Foo(object):
#Turn the method foo to a class method
@classmethod
def foo(self):
print("foo is called")
pass
if __name__ == '__main__':
Foo.foo()
pass
代碼量減少了,可讀性也強了,函數的特性也很直觀。
3. 當前語法
當前Python
的裝飾器語法如下:
@dec2
@dec1
def func(arg1, arg2, ...):
pass
上面的代碼相當于:
def func(arg1, arg2, ...):
pass
func = dec2(dec1(func))
4. 裝飾器的更多用法示例
我們可以使用Python
裝飾器來更加直接了當地使用
staticmethod()
和
classmethod()
內置函數,但裝飾器的作用遠不止于此。
1.例如我們要定義一個函數,當程序退出的時候調用此函數。
def onexit(f):
import atexit
atexit.register(f)
return f
@onexit
def func():
...
注意在真實場景中我們可能不會這么做,上面代碼只是用作示例。
2.使用Python
裝飾器實現單例模式。
def singleton(cls):
instances = {}
def getinstance():
if cls not in instances:
instances[cls] = cls()
return instances[cls]
return getinstance
@singleton
class MyClass:
...
3.給函數添加屬性。
def attrs(**kwds):
def decorate(f):
for k in kwds:
setattr(f, k, kwds[k])
return f
return decorate
@attrs(versionadded="2.2",
author="Guido van Rossum")
def mymethod(f):
...
4.聲明類實現了某些接口。
def provides(*interfaces):
"""
An actual, working, implementation of provides for
the current implementation of PyProtocols. Not
particularly important for the PEP text.
"""
def provides(typ):
declareImplementation(typ, instancesProvide=interfaces)
return typ
return provides
class IBar(Interface):
"""Declare something about IBar here"""
@provides(IBar)
class Foo(object):
"""Implement something here..."""