類裝飾器包含普通類作為乙個裝飾器,
同時描述符類作為乙個裝飾器的2種方式;
類裝飾器需要小心使用的一點是當作用於另乙個類(被裝飾的類)方法時, 被裝飾的類的self傳遞的問題(見下面例子)
結論:如果要編寫乙個既適用函式也適用類方法的裝飾器,要麼是用函式裝飾器,要麼是用描述符裝飾器
#類裝飾器與函式裝飾器的一些錯誤應用
#以下2個tracer 功能一樣
#類裝飾器
class tracer:
def __init__(self,func): #接受乙個函式物件
self.calls = 0
self.func = func
def __call__(self, *args, **kwargs):
self.calls += 1
print('類裝飾器:call %s to %s'%(self.calls,self.func.__name__),',args:',*args)
return self.func(*args,**kwargs) #呼叫函式
#函式裝飾器
def tracer_func(func):
calls = 0 # 呼叫次數
def on_call(*args, **kwargs):
nonlocal calls
calls += 1
print('函式裝飾器:call %s to %s' % (calls, func.__name__), ',args:', *args)
return func(*args,**kwargs)
return on_call
#類裝飾器作用於函式上
@tracer
def testfunc(x,y): #此時testfunc是乙個tracer例項
print(x,y)
testfunc(1,2) #ok,呼叫tracer.__call__()
#echo:
#call 1 to testfunc
#def spam: 1 2
#類裝飾器作用於類方法上
class person:
def __init__(self,name='person'):
self.name = name
@tracer
def lastname(self): #lastname 是乙個tracer例項
return self.name.split()[-1]
p = person()
#print(p.lastname())
#這裡將會出錯
#lastname是乙個tracer例項,lastname(),相當於tracer(),tracer例項本身作為self傳遞進了__call__ ,而person例項並未傳遞進去
#函式裝飾器作用於類方法
class person1:
def __init__(self,name='person'):
self.name = name
@tracer_func
def lastname(self): #lastname = tracer_func(lastname),
return self.name.split()[-1]
p = person1()
print(p.lastname()) #呼叫on_call , p 被傳入進*args
#使用描述符作為裝飾器
#使用描述符來作裝飾器的理由是__get__(self,instance,owner)
#能夠接受2個例項物件, 乙個是描述符本身,還有乙個是被裝飾的物件
#描述符物件作裝飾器能彌補普通類作裝飾器無法很好的作用於類的方法上
class tracer:
def __init__(self,func): #描述符接受乙個函式物件
self.calls = 0
self.func = func
def __call__(self, *args, **kwargs): #能用於函式裝飾器
self.calls += 1
print('tracer call %s to %s'%(self.calls,self.func.__name__), ',args:' , args)
return self.func(*args,**kwargs)
def __get__(self, instance, owner): #__get__ 獲取2個例項物件,1個self(描述符物件) , instance(被裝飾的物件)
print('__get__')
#包裝類,接受2個引數,1個是描述符物件,用於描述符__get__的返回值
def __init__(self,desc,instance):
self.desc = desc
self.instance = instance
def __call__(self, *args, **kwargs): #用於函式呼叫
return self.desc(self.instance,*args,**kwargs) #呼叫tracer的__call__
class person:
def __init__(self, name='person'):
self.name = name
@tracer
def lastname(self): # lastname 是乙個tracer例項
return self.name.split()[-1]
p = person()
print(p.lastname())
描述符作為裝飾器的另一種方法, 把tracer描述符類修改__get__ 中的一些**,更好的實現:
class tracer:def __init__(self,func): #描述符接受乙個函式物件
self.calls = 0
self.func = func
def __call__(self, *args, **kwargs): #能用於函式裝飾器
self.calls += 1
print('tracer call %s to %s'%(self.calls,self.func.__name__), ',args:' , args)
return self.func(*args,**kwargs)
def __get__(self, instance, owner): #__get__ 獲取2個例項物件,1個self(描述符物件) , instance(被裝飾的物件)
print('__get__')
return self(instance,*args,**kwargs)
函式裝飾器與類的裝飾器
先說函式的裝飾器,如下 1 defzhuang func 2print 3return func 高階函式45 6 zhuang 相當於是test zhuang test 7def test 8print 910 test view code 其實所有的 語法糖,都可以像 中注釋的那樣等於 類的裝飾...
函式裝飾器 類裝飾器
一 函式裝飾函式 defwrapfun func definner a,b print function name func.name r func a,b return r return inner wrapfun defmyadd a,b return a b print myadd 2,3 二...
python裝飾器 函式裝飾器,類裝飾器
只要實現此 模式,這個obj就叫乙個裝飾器 參考 函式裝飾器 例子 def decorator func def inner args,kwargs print before.res func args,kwargs print after.return res return inner decor...