###先來看看乙個列子
def foo():
print '我是lxshen'
foo()
輸出:我是lxshen
這時我想在這個輸出前面再執行一段程式。這時我們首先想到的是以下兩種方法:
方法一:直接在函式中新增
def foo():
print 'hello,'
print '我是lxshen'
foo()
輸出:hello, 我是lxshen
方法二:我再另寫乙個函式,再foo函式中呼叫
def foo():
fee()
print '我是lxshen'
def fee():
print 'hello,'
foo()
輸出:hello, 我是lxshen
這樣一看,你可能會說這兩種方法好像第一種更加方便,那麼我只能呵呵了,由於我這裡只是舉乙個列子,你可以想象要新增的一段**,**量是100行甚至更多,並且要在幾十個函式中新增。那麼這時候你會選擇哪個方法?反正我是選擇第二種,不然會死人的。###裝飾器
這樣你以為就完了嗎,一般在開發過程中,要遵循開放封閉原則,雖然在這個原則是用的物件導向開發,但是也適用於函式式程式設計,簡單來說,它規定已經實現的功能**不允許被修改,但可以被擴充套件,即:乙個簡單的裝飾器:
def fee(func): # 需要傳遞乙個函式
def wrap(): # 如果這個函式需要傳遞引數,那麼所需要引數就寫在這裡
print 'hello,'
return func()
return wrap
def foo():
print '我是lxshen'
f = fee(foo) # f 等價於 wrap
f() # wrap()
輸出:hello, 我是lxshen
函式fee就是裝飾器,它把執行真正業務邏輯**的foo包裹在函式裡面,看起來像bar被use_logging裝飾了。在這個例子中,函式進入和對出是,被稱為乙個橫切面(aspect),這種程式設計方式被稱為面向切面的程式設計(aspect-oriented programming)使用』語法糖』@
@符號是裝飾器的』語法糖』,在定義函式的時候使用,避免再一次賦值操作
def fee(func):
def wrap():
print 'hello,'
func()
return wrap
@fee
def foo():
print '我是lxshen'
foo()
輸出:hello, 我是lxshen
foo() 可以理解為:
foo = fee(foo)
# foo先作為引數賦值給func後,foo接收指向fee返回的wrap
foo()
# 呼叫foo(),即等價呼叫wrap()
# 內部函式wrap被引用,所以外部函式的func變數(自由變數)並沒有釋放
# func裡儲存的是原foo函式物件
如果我們有其他的類似函式,我們可以繼續呼叫裝飾器來修飾函式,而不用重複修改函式或者增加新的封裝。這樣,我們就提高了程式的可重複利用性,並增加了程式的可讀性。####2.被裝飾的函式有引數
def fee(func):
def wrap(gold):
print 'hello,'
func(gold)
return wrap
@fee
def foo(gold):
print gold
print '我是lxshen'
@fee
def faa(gold):
print gold
print '我是xiaoming'
faa('lxshen')
輸出:hello, lxshen 我是xiaoming
在閉包wrap中執行func函式(即執行foo函式),既然func需要乙個引數,那麼閉包warp就需要乙個新增引數。如果還是不理解,可以把 這個例子拆開成『乙個簡單的裝飾器』的樣子來看。####3.修飾器帶引數
def user(name):
def fee(func):
def wrap(gold):
if name == 'lxshen':
print 'hello,'
elif name == 'xiaoming':
print '你好,'
func(gold)
return wrap
return fee
@user(name='lxshen')
def foo(gold):
print gold
print '我是lxshen'
@user(name='xiaoming')
def faa(gold):
print gold
print '我是xiaoming'
faa('lxshen')
上面的user是允許帶引數的裝飾器。他實際上是對原有裝飾器的乙個函式封裝,並返回乙個裝飾器。我們可以將它理解我乙個含有引數的閉包。####4.類裝飾器
裝飾器函式其實是這樣乙個介面約束,它必須接受乙個callable物件作為引數,然後返回乙個callable物件。在python中一般callable物件都是函式,但也有例外。只要某個物件重寫了call() 方法,那麼這個物件就是callable的。
class fee(object):
def __init__(self,func):
self._func = func
def __call__(self, name):
print 'hello'
self._func(name)
@fee
def foo(gold):
print gold
print 'lxshen'
輸出:分析:
#1.當用fee來裝作裝飾器對foo函式進行裝飾的時候,首先會建立fee的例項物件
# 並且會把foo這個函式名當做引數傳遞到__init__方法中
# 即在__init__方法中的func變數指向了foo函式體
#2. foo函式相當於指向了用fee建立出來的例項物件
##3. 當在使用foo()進行呼叫時,就相當於讓這個物件(),因此會呼叫這個物件的__call__方法
##4. 為了能夠在__call__方法中呼叫原來foo指向的函式體,所以在__init__方法中就需要乙個例項屬性來儲存這個函式體的引用
# 所以才有了self.__func = func這句**,從而在呼叫__call__方法中能夠呼叫到foo之前的函式體
###總結:
1.什麼時候使用裝飾器?
一般在開發過程中,要遵循開放封閉原則,雖然在這個原則是用的物件導向開發,但是也適用於函式式程式設計,簡單來說,它規定已經實現的功能**不允許被修改,但可以被擴充套件,這時就要使用裝飾器了。2.使用裝飾器來修飾函式
不改變原有的程式,並且可以新增新的功能
可以提高程式的可重複利用性,並增加了程式的可讀性。
python裝飾器 Python 裝飾器
簡言之,python裝飾器就是用於拓展原來函式功能的一種函式,這個函式的特殊之處在於它的返回值也是乙個函式,使用python裝飾器的好處就是在不用更改原函式的 前提下給函式增加新的功能。一般而言,我們要想拓展原來函式 最直接的辦法就是侵入 裡面修改,例如 這是我們最原始的的乙個函式,然後我們試圖記錄...
python裝飾器 裝飾器
由於函式也是乙個物件,而且函式物件可以被賦值給變數,所以,通過變數也能呼叫該函式。def now print 2015 3 25 f now f 2015 3 25 函式物件有乙個 name 屬性,可以拿到函式的名字 now.name now f.name now 現在,假設我們要增強now 函式的...
python裝飾器原理 Python裝飾器原理
裝飾器 decorator 是物件導向設計模式的一種,這種模式的核心思想是在不改變原來核心業務邏輯 的情況下,對函式或類物件進行額外的修飾。python中的裝飾器由python直譯器直接支援,其定義形式如下 decorator def core service 要理解上述 的含義,我們從自定義函式裝...