》眼花繚亂
Python的裝飾器(也稱語法糖)大致分為這幾類:
- 無參數(shù)裝飾器
- 有參數(shù)裝飾器
- 裝飾類的裝飾器
- 無參數(shù)類裝飾器
- 有參數(shù)類裝飾器
:()磕洪,這幾個(gè)分類待會(huì)兒一個(gè)一個(gè)解釋,有可能叫法不一定對(duì)。光是分類就這么多了,如果在弄不清楚裝飾器的本質(zhì),不知要死多少腦細(xì)胞淤堵,媽媽啊、顷扩、拐邪、、隘截、
》撥云見日
我們閑聊點(diǎn)別的扎阶,先看這樣一個(gè)問題:假設(shè)我用了一個(gè)別人的函數(shù)f汹胃,我想加入自己的邏輯,比如在f執(zhí)行前后打印日志东臀,你可能這樣實(shí)現(xiàn):
def outer_one(f):
print 'outer_1 before'
f()
print 'outer_1 after'
好像實(shí)現(xiàn)了功能着饥,但是只是實(shí)現(xiàn)了部分功能,而且我們希望是一個(gè)新函數(shù)惰赋,如何實(shí)現(xiàn)呢宰掉??赁濒?轨奄?
你問我,可我也不知道拒炎,我們分析一下挪拟,既然是新函數(shù),假設(shè)返回一個(gè)函數(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)該是這樣吧
》來點(diǎn)困難的
上面的只是開開眼球切,下面來點(diǎn)難的:
# 無參數(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)))吨凑,這個(gè)表達(dá)式返回的是個(gè)函數(shù),new_func.__name__ 是什么户辱?思考一下再回來鸵钝、、庐镐、
哈哈恩商,第二個(gè)答案是outer_three的wrapped3。
這個(gè)問題的關(guān)鍵是弄清outer_three(outer_two(outer_one(f)))這個(gè)表達(dá)式是如何執(zhí)行的必逆,它是從內(nèi)到外執(zhí)行的怠堪,也就是,outer_one返回的wrapped1會(huì)作為outer_two的參數(shù)名眉,即粟矿,f=wrapped1。
再來點(diǎn)復(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)用圖如下:
》言歸正傳
我們看個(gè)栗子:
# 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 "++++++++++++++++++++++="
其實(shí)這個(gè)語法糖幫你做了一個(gè)這樣的事情,func = wrapper_func(func)
__這就是裝飾器的本質(zhì) __
師兄只能幫你到這里了福压,剩下的看你了 :------》,
什么還不懂掏秩,再提示幾點(diǎn)或舞,
- 有參數(shù)時(shí),func = wrapper_func(args1)(func)(args2)蒙幻,args1傳給了wrapper_func()映凳,而args2 傳給了func
- 對(duì)于class,如果想這樣用杆煞,MyClass(args)(args),需要重寫MyClass的__call__方法
- 考慮下魏宽,func在什么時(shí)候被調(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铆惑, 裝飾器是一個(gè)類, 無參數(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范嘱, 裝飾器是一個(gè)類,有參數(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 "++++++++++++++++++++++="