》眼花繚亂
Python的裝飾器(也稱語法糖)大致分為這幾類:
- 無參數(shù)裝飾器
- 有參數(shù)裝飾器
- 裝飾類的裝飾器
- 無參數(shù)類裝飾器
- 有參數(shù)類裝飾器
:(),這幾個分類待會兒一個一個解釋,有可能叫法不一定對。光是分類就這么多了,如果在弄不清楚裝飾器的本質(zhì),不知要死多少腦細(xì)胞,媽媽啊、、、、、
》撥云見日
我們閑聊點別的,先看這樣一個問題:假設(shè)我用了一個別人的函數(shù)f,我想加入自己的邏輯,比如在f執(zhí)行前后打印日志,你可能這樣實現(xiàn):
def outer_one(f):
print 'outer_1 before'
f()
print 'outer_1 after'
好像實現(xiàn)了功能,但是只是實現(xiàn)了部分功能,而且我們希望是一個新函數(shù),如何實現(xiàn)呢????
你問我,可我也不知道,我們分析一下,既然是新函數(shù),假設(shè)返回一個函數(shù),貌似問題解決了,于是我們有了下面的實現(xiàn):
def outer_one(f):
def wrapped():
print 'outer_1 before'
f()
print 'outer_1 after'
return wrapped
這樣,令new_func=wrapped(f),調(diào)用new_func(),貌似就應(yīng)該是這樣吧
》來點困難的
上面的只是開開眼,下面來點難的:
# 無參數(shù)
def outer_three(f):
def wrapped3():
print 'outer_3 before'
f()
print 'outer_3 after'
return wrapped3
def outer_two(f):
def wrapped2():
print 'outer_two before'
f()
print 'outer_two after'
return wrapped2
def outer_one(f):
def wrapped1():
print 'outer_1 before'
f()
print 'outer_1 after'
return wrapped1
def f():
print 'f'
print "++++++++++++++++++++++="
outer_three(outer_two(outer_one(f)))()
print f.__name__
print "++++++++++++++++++++++="
你能猜猜結(jié)果嘛,特別關(guān)注,new_func=outer_three(outer_two(outer_one(f))),這個表達(dá)式返回的是個函數(shù),new_func.__name__ 是什么?思考一下再回來、、、
哈哈,第二個答案是outer_three的wrapped3。
這個問題的關(guān)鍵是弄清outer_three(outer_two(outer_one(f)))這個表達(dá)式是如何執(zhí)行的,它是從內(nèi)到外執(zhí)行的,也就是,outer_one返回的wrapped1會作為outer_two的參數(shù),即,f=wrapped1。
再來點復(fù)雜的,如果要傳遞參數(shù)該怎么寫呢?
# 有參數(shù)
def outer_three(f):
def wrapped(a):
print 'outer_3 before'
f(a)
print 'outer_3 after'
return wrapped
def outer_two(f):
def wrapped(a):
print 'outer_two before'
f(a)
print 'outer_two after'
return wrapped
def outer_one(f):
def wrapped(a):
print 'outer_1 before'
f(a)
print 'outer_1 after'
return wrapped
def f(a):
print 'f:',a
print "++++++++++++++++++++++="
outer_three(outer_two(outer_one(f)))(123132)
print f.__name__
print "++++++++++++++++++++++="
調(diào)用圖如下:

》言歸正傳
我們看個栗子:
# first,無參數(shù)裝飾器
def wrapper_func(f):
print f.name
def wrapped(a):
f(a)
return wrapped
@wrapper_func
def func(a):
print a
print locals()
print "++++++++++++++++++++++="
func(234)
print func
print "++++++++++++++++++++++="
其實這個語法糖幫你做了一個這樣的事情,func = wrapper_func(func)
__這就是裝飾器的本質(zhì) __
師兄只能幫你到這里了,剩下的看你了 :------》,
什么還不懂,再提示幾點,
- 有參數(shù)時,func = wrapper_func(args1)(func)(args2),args1傳給了wrapper_func(),而args2 傳給了func
- 對于class,如果想這樣用,MyClass(args)(args),需要重寫MyClass的__call__方法
- 考慮下,func在什么時候被調(diào)包了
- 考慮下,現(xiàn)在的func的名字已經(jīng)不是func了,如何讓它的名字恢復(fù)
- 如果有返回值該怎么辦?return
好了,代碼如下:
# first,無參數(shù)裝飾器
def wrapper_func(f):
print f.__name__
def wrapped(a):
f(a)
return wrapped
@wrapper_func
def func(a):
print a
print locals()
print "++++++++++++++++++++++="
func(234)
print func
print "++++++++++++++++++++++="
# second,有參數(shù)裝飾器
def wrapper_one(arg):
print 's:',arg
def wrapper_two(f):
def wrapper_three(a):
print 'a', a
f(a)
return wrapper_three
return wrapper_two
@wrapper_one('sfdsf')
def func2(s):
print s
print "++++++++++++++++++++++="
func2(34)
print func2
print "++++++++++++++++++++++="
# three, 裝飾類的裝飾器
def wrapper_cls(cls):
def wrapperd_cls(*args,**kwgs):
cls(*args,**kwgs)
return wrapperd_cls
@wrapper_cls
class MyClass(object):
pass
print "++++++++++++++++++++++="
print MyClass()
print MyClass
print "++++++++++++++++++++++="
# four, 裝飾器是一個類, 無參數(shù)
class wrapper_class(object):
def __init__(self,func):
self.func=func
def __call__(self,*args,**kwgs):
self.func(*args,**kwgs)
@wrapper_class
def func3(a):
print a
print "++++++++++++++++++++++="
print func3(5)
print func3
print "++++++++++++++++++++++="
# four, 裝飾器是一個類,有參數(shù)
class wrapper_class2(object):
def __init__(self,args):
print 'cls',args
def __call__(self,func):
def wrapper_inner(*args,**kwgs):
func(*args,**kwgs)
return wrapper_inner
@wrapper_class2(123)
def func4(a):
print a
print "++++++++++++++++++++++="
print func4(5)
print func4
print "++++++++++++++++++++++="