1.函數裝飾器
-
裝飾器的定義:裝飾器其實就是一個閉包,把一個函數當作參數傳進去,然後返回一個替代版函數
-
裝飾器主要的分類:
-
裝飾器對無參數的函數進行裝飾,對一個函數可以使用多個裝飾器,執行順序由內向外
#定義函數:完成包裹數據 def makeBold(fn): def wrapped(): return "<b>" + fn() + "</b>" return wrapped #定義函數:完成包裹數據 def makeItalic(fn): def wrapped(): return "<i>" + fn() + "</i>" #當有return時,適用於有返回和無返回的函數 return wrapped @makeBold def test1(): return "hello world - 1" @makeItalic def test2(): return "hello world - 2" @makeBold @makeItalic def test3(): return "hello world - 3" print(test1()) print(test2()) print(test3()) ######執行結果 <b>hello world - 1</b> <i>hello world - 2</i> <b><i>hello world - 3</i></b> Process finished with exit code 0
-
裝飾器對有參數函數進行裝飾
#定義一個裝飾器 def deco(func): # 內部函數的參數必須和被裝飾的函數保持一致 def wrapper(a, b): print("獲得被修飾函數的參數:a= %s,b= %s" % (a, b)) return func(a, b) return wrapper #有參數的函數 @deco def sum(a, b): return a+b print(sum(10, 20)) ######執行結果 獲得被修飾函數的參數:a= 10,b= 20 30 Process finished with exit code 0
-
裝飾器對可變參數函數進行裝飾
#定義一個裝飾器,裝飾不定長參數函數 def deco(func): def wrapper(*args,**kwargs): print("arguments args length : %d" % len(args)) print("arguments kwargs length : %d" % len(kwargs)) func(*args,**kwargs) return wrapper @deco def test1(a, b, c): print(a+b+c) @deco def test2(a, b): print(a+b) @deco def test3(*args,**kwargs): print(args) print(kwargs) print("*************") test1(10, 20, 30) print("*************") test2(10, 20) print("*************") test3(1, 2, 3, d=4, x=5) ######執行結果 ************* arguments args length : 3 arguments kwargs length : 0 60 ************* arguments args length : 2 arguments kwargs length : 0 30 ************* arguments args length : 3 arguments kwargs length : 2 (1, 2, 3) {'d': 4, 'x': 5} Process finished with exit code 0
-
帶參數的裝飾器
def decrorator_args_func(): print("This is a warpper function") def decrorator_func(decrorator_func_arg): decrorator_func_arg() def decr_outter_func(func): def decr_inner_func(*args,**kwargs): func(*args,**kwargs) print("I am a decrorator inner function") return decr_inner_func return decr_outter_func @decrorator_func(decrorator_args_func) def warpped_func(a, b): print("I am a wapped function") warpped_func('s', 'b') ######執行結果 This is a warpper function I am a wapped function I am a decrorator inner function Process finished with exit code 0
-
-
如果多個函數被兩個裝飾器裝飾時就報錯,因爲兩個函數名一樣,第二個函數再去裝飾的話就報錯。增加@functools.wraps(f), 可以保持當前裝飾器去裝飾的函數的 name 的值不變
import functools def user_login_data(f): @functools.wraps(f) def wrapper(*args, **kwargs): return f(*args, **kwargs) return wrapper @user_login_data def num1(): print("aaa") @user_login_data def num2(): print("bbbb") if __name__ == '__main__': print(num1.__name__) print(num2.__name__) ######執行結果 num1 num2 Process finished with exit code 0
2. 類裝飾器
-
類裝飾器概念:類裝飾器的裝飾方法跟函數裝飾器相同,都是使用@語法,但是由於類本身不可直接被調用執行,因此必須在類中實現call( )方法。
-
類裝飾器的分類:
-
裝飾無參數的類裝飾器
# 僅執行函數 class FuncLog(): def __init__(self, func): print('exec funcLog __init__') self._func = func # 類裝飾器中,要有call方法 def __call__(self): print('exec funcLog __call__') return self._func() #當有return時,適用於有返回和無返回的函數 @FuncLog def demoFunc(): print( 'This is a demo function......') @FuncLog def demoFunc2(): return 'This is a demo function......' demoFunc() print(demoFunc2()) #########執行結果 exec funcLog __init__ exec funcLog __init__ exec funcLog __call__ This is a demo function...... exec funcLog __call__ This is a demo function.....1111. Process finished with exit code 0
-
裝飾有參數的類裝飾器
# 執行函數,被修飾函數存在參數 class FuncLog(): def __init__(self, func): print('exec funcLog __init__') self._func = func # 類裝飾器中,要有call方法 def __call__(self, *args, **kwargs): print('exec funcLog __call__') print('function args : %s '% args) self._func(*args, **kwargs) @FuncLog def demoFunc(func_args): print('This is a demo function, Args is : %s' % func_args) demoFunc('20190726') #########執行結果 exec funcLog __init__ exec funcLog __call__ function args : 20190726 This is a demo function, Args is : 20190726 Process finished with exit code 0
-
裝飾有參數的類裝飾器,並且裝飾器有參數
import functools # 執行函數,被修飾函數存在參數,並且裝飾器有入參 class FuncLog(): def __init__(self, func_log_arg): print('exec funcLog __init__') self._func_log_arg = func_log_arg # 類裝飾器中,要有call方法 def __call__(self, func): print('exec funcLog __call__') print('decr args is :%s' % self._func_log_arg) @functools.wraps(func) def wrapper(*args, **kwargs): print('function args : %s ' % args) return func(*args, **kwargs) return wrapper @FuncLog('decr_log') def demoFunc(func_args): print('This is a demo function, Args is : %s' % func_args) demoFunc('20190726') print(demoFunc.__name__) ###########執行結果 exec funcLog __init__ exec funcLog __call__ decr args is :decr_log function args : 20190726 This is a demo function, Args is : 20190726 demoFunc Process finished with exit code 0
-
3. super關鍵字
-
定義: super([type[, object-or-type]]) ,super() 在使用時至少傳遞一個參數,且這個參數必須是一個類。通過super()獲取到的是一個代理對象,通過這個對象去查找父類或者兄弟類的方法。
-
集中常用的寫法:
-
super()不寫參數的情況:super() 在一個定義的類中使用時,可以不寫參數,Python會自動根據情況將兩個參數傳遞給super。在Python3中的類都是新式類,廣度優先的查找順序,在定義一個類時就會生成一個MRO列表(經典類沒有MRO列表,深度優先),查找順序就是按照這個列表中的類的順序從左到右進行的。
class Base: def __init__(self): print('Base.__init__') class A(Base): def __init__(self): super().__init__() print('A.__init__') class B(Base): def __init__(self): super().__init__() print('B.__init__') class C(Base): def __init__(self): super().__init__() print('C.__init__') class D(A, B, C): def __init__(self): super().__init__() # 等同於 super(D, self).__init__() print('D.__init__') D() print(D.mro()) #結果 Base.__init__ C.__init__ B.__init__ A.__init__ D.__init__ [<class '__main__.D'>, <class '__main__.A'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.Base'>, <class 'object'>]
-
super(type) 只傳遞一個參數的情況:super() 只傳遞一個參數時,是一個不綁定的對象,不綁定的話它的方法是不會有用的
class Base: def __init__(self): print('Base.__init__') class A(Base): def __init__(self): super().__init__() print('A.__init__') class B(Base): def __init__(self): super().__init__() print('B.__init__') class C(Base): def __init__(self): super().__init__() print('C.__init__') class D(A, B, C): def __init__(self): super(B).__init__() # 值傳遞一個參數 print('D.__init__') D() print(D.mro()) #結果 D.__init__ [<class '__main__.D'>, <class '__main__.A'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.Base'>, <class 'object'>]
-
super(type, obj) 傳遞一個類和一個對象的情況:super() 的參數爲一個類和一個對象的時候,得到的是一個綁定的super對象。但是obj必須是type的實例或者是子類的實例。 從結果可以看出,只是查找了B類之後的類的方法,即super()是根據第二個參數(obj)來計算MRO,根據順序查找第一個參數(類)之後的類的方法
class Base: def __init__(self): print('Base.__init__') class A(Base): def __init__(self): super().__init__() print('A.__init__') class B(Base): def __init__(self): super().__init__() print('B.__init__') class C(Base): def __init__(self): super().__init__() print('C.__init__') class D(A, B, C): def __init__(self): super(B, self).__init__() # self是B的子類D的實例 print('D.__init__') D() print(D.mro()) #結果 Base.__init__ C.__init__ D.__init__ [<class '__main__.D'>, <class '__main__.A'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.Base'>, <class 'object'>]
-
super(type1, type2) 傳遞兩個類的情況:super()傳遞兩個類type1和type2時,得到的也是一個綁定的super對象,但這需要type2是type1的子類,且如果調用的方法需要傳遞參數時,必須手動傳入參數,因爲super()第二個參數是類時,得到的方法是函數類型的,使用時不存在自動傳參,第二個參數是對象時,得到的是綁定方法,可以自動傳參。
class Base: def __init__(self): print('Base.__init__') class A(Base): def __init__(self): super().__init__() print('A.__init__') class B(Base): def __init__(self): super().__init__() print('B.__init__') class C(Base): def __init__(self): super().__init__() print('C.__init__') class D(A, B, C): def __init__(self): super(B, D).__init__(self) # D是B的子類,並且需要傳遞一個參數 print(type(super(B, D).__init__)) #返回的Function,需要自己填充參數 print(type(super(B, self).__init__)) #返回的是method,python自動填充參數 print('D.__init__') D() print(D.mro()) #結果 Base.__init__ C.__init__ <class 'function'> <class 'method'> D.__init__ [<class '__main__.D'>, <class '__main__.A'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.Base'>, <class 'object'>]
-