Python類(lèi)中的裝飾器在當(dāng)前類(lèi)中的聲明與調(diào)用詳解
我的Python環(huán)境:3.7
在Python類(lèi)里聲明一個(gè)裝飾器,并在這個(gè)類(lèi)里調(diào)用這個(gè)裝飾器。
代碼如下:
class Test(): xx = False def __init__(self): pass def test(func): def wrapper(self, *args, **kwargs): print(self.xx) return func(self, *args, **kwargs) return wrapper @test def test_a(self,a,b): print(f'ok,{a} ')
注意:
1. 其中裝飾器test是在類(lèi)Test中聲明并在其方法test_a中調(diào)用
2. 裝飾器test內(nèi)層wrapper函數(shù)的首參數(shù)是self
補(bǔ)充知識(shí):python-類(lèi)內(nèi)函數(shù)的全局裝飾器
有時(shí),比如寫(xiě)RF的測(cè)試庫(kù)的時(shí)候,很多方法都寫(xiě)在一個(gè)類(lèi)里。我們又可能需要一個(gè)通用的裝飾器,比如,要給某個(gè)底層類(lèi)的方法打樁,查看入?yún)⒑统鰠ⅲ靡岳斫鈽I(yè)務(wù);或者要hold住所有的執(zhí)行錯(cuò)誤,打印堆棧又不想程序退出或用例直接失敗
比如捕捉錯(cuò)誤的裝飾器
import traceback from functools import wraps def trier(soft=False): ''' :param bool soft: 為T(mén)rue時(shí),打印報(bào)錯(cuò)堆棧并忽略異常。默認(rèn)False,打印報(bào)錯(cuò)堆棧并拋出異常 :return: 如果要給類(lèi)方法、靜態(tài)方法裝飾,則該裝飾器必須處于比@staticmethod裝飾器更內(nèi)一層才行 ''' def realTrier(func): ''' :param function func: :return: ''' @wraps(func) # 保留__name__ __doc__ __module__ def innerfunc(*args, **kwargs): try: return func(*args, **kwargs) except Exception, e: try: print(traceback.format_exc()) except: print e if not soft: raise return innerfunc return realTrier
或者參數(shù)跟蹤的裝飾器
def tracer(func): def infunc(*args, **kwargs): print func.__name__, args, kwargs res=infunc(*args, **kwargs) print func.__name__, res return res
這類(lèi)裝飾器經(jīng)常會(huì)給類(lèi)里的每個(gè)函數(shù)都使用
每次都裝飾的話(huà),也挺麻煩
python里可以給類(lèi)寫(xiě)個(gè)裝飾器,所以可以輸入一個(gè)類(lèi),返回一個(gè)新類(lèi),這個(gè)新類(lèi)擁有原來(lái)類(lèi)里的所有方法,但所有方法都被裝飾
使用元類(lèi),可以做到這一點(diǎn)。
目前可以批量裝飾普通方法、靜態(tài)方法、類(lèi)方法、屬性,暫不支持__init__和__del__之類(lèi)的特殊方法,以免出現(xiàn)意外的問(wèn)題。
目前類(lèi)B使用了全局裝飾器,假如類(lèi)B繼承自類(lèi)A,類(lèi)C繼承自類(lèi)B
則類(lèi)B、類(lèi)C內(nèi)的所有方法都被全局裝飾(全局裝飾可以被繼承)
且類(lèi)B繼承自類(lèi)A的所有方法也會(huì)被全局裝飾
但這種裝飾不會(huì)影響到類(lèi)A,調(diào)用類(lèi)A下的方法時(shí),所有方法都不被裝飾
經(jīng)過(guò)多次嘗試,最后的實(shí)現(xiàn)代碼如下
# clswrapper.py def skipper(func): ''' :param function func: :return: ''' func.__funskip__=True return func def classWrapper(commonDecoratorFunc): def innerMata(inClass): def collect_attrib(key, value, new_attrs): if hasattr(value, '__funskip__'): new_attrs[key] = value return if hasattr(value, '__func__') or isinstance(value, types.FunctionType): if isinstance(value, staticmethod): new_attrs[key] = staticmethod(commonDecoratorFunc(value.__func__)) return elif isinstance(value, classmethod): new_attrs[key] = classmethod(commonDecoratorFunc(value.__func__)) return elif not key.startswith('__'): new_attrs[key] = commonDecoratorFunc(value) return else: if isinstance(value, property): # 當(dāng)對(duì)property類(lèi)進(jìn)行重組的時(shí)候,我們強(qiáng)制裝飾了property類(lèi)的fget fset和fdel方法。但是,不是每個(gè)propery都有這三個(gè)方法,有些是None,強(qiáng)制裝飾會(huì)報(bào)錯(cuò),所以我們這里要考慮提前返回None propertyWrapper = property(fget=commonDecoratorFunc(value.fget) if value.fget else None, fset=commonDecoratorFunc(value.fset) if value.fset else None, fdel=commonDecoratorFunc(value.fdel) if value.fdel else None, doc=value.__doc__) new_attrs[key] = propertyWrapper return new_attrs[key] = value class Meta(type): @classmethod def options(cls, bases, attrs): new_attrs = {} for key, value in attrs.items(): collect_attrib(key, value, new_attrs) for base in bases: for mbase in base.mro(): for key, value in mbase.__dict__.items(): if key not in new_attrs: collect_attrib(key, value, new_attrs) return new_attrs def __new__(cls, name, bases, attrs): new_attrs = cls.options(bases, attrs) return super(Meta, cls).__new__(cls, name, bases, new_attrs) return six.add_metaclass(Meta)(inClass) return innerMata
其中,skipper提供了一個(gè)后門(mén),被skipper裝飾的函數(shù)會(huì)跳過(guò)全局裝飾器
使用方法如下
@classWrapper(trier(soft=True)) class Tree(object): @skipper def div(self): return 1/0 def divsafe(self): return 1/0 t=Tree() print t.divsafe() print t.div()
執(zhí)行結(jié)果如圖
一個(gè)更完整的示例
from clswrapper那個(gè)文件 import skipper, classWrapper import traceback from functools import wraps '''為簡(jiǎn)潔起見(jiàn),這次我們用的是不帶參數(shù)的trier裝飾器''' def trier(func): @wraps(func) def inner(*args, **kwargs): try: return func(*args, **kwargs) except: print("EXCEPTION captured at function %s" % func.__name__, file=sys.stderr) print(traceback.format_exc().decode("gbk")) raise return inner if __name__=="__main__": import time class mobj(object): def five(self): w = 1 / 0 class obj(mobj): def __init__(self): # print "obj.__init__" return @classmethod def one(self): w = 1 / 0 print('obj.one') @classWrapper(trier) # 或者用@classWrapper(argTrier(True))替換,則可以不拋出異常 class obj1(obj): aa = 1 def __init__(self): super(obj1, self).__init__() self.var = 1 @classmethod def three(cls): w = 1 / 0 print('obj1.three') @staticmethod def four(): w = 1 / 0 print('obj1.four') def two(self): w = 1 / 0 print(self.pro) print('obj1.two') @property def pro(self): return self.var @pro.setter def pro(self, value): self.var = value / 0 @skipper def eight(self): w=1/0 return w class outerobj(obj1): def seven(self): return 1/0 b = obj1() a = obj1 print(b.var) try: b.two() except: pass try: a.three() except: pass try: a.four() except: pass try: a.one() except: pass try: b.five() except: pass try: b.pro = 3 except: pass print(b.pro) print(a.aa) c=outerobj() try: c.five() except: pass try: c.seven() except: pass try: c.eight() except: print("c.eight被跳過(guò),所以沒(méi)有被里層捕獲,才會(huì)不打堆棧直接走到這里") print("最后這個(gè)會(huì)真正觸發(fā)異常,因?yàn)閙obj實(shí)例并沒(méi)有被裝飾過(guò)") m=mobj() time.sleep(1) m.five()
它展示了這個(gè)強(qiáng)大裝飾器能處理的各種情況,執(zhí)行結(jié)果應(yīng)該如下
1 EXCEPTION captured at function two EXCEPTION captured at function three Traceback (most recent call last): EXCEPTION captured at function four File "E:/pydev/異常處理裝飾器.py", line 37, in inner EXCEPTION captured at function one return func(*args, **kwargs) EXCEPTION captured at function five File "E:/pydev/異常處理裝飾器.py", line 138, in two w = 1 / 0 ZeroDivisionError: integer division or modulo by zero Traceback (most recent call last): File "E:/pydev/異常處理裝飾器.py", line 37, in inner return func(*args, **kwargs) File "E:/pydev/異常處理裝飾器.py", line 129, in three w = 1 / 0 ZeroDivisionError: integer division or modulo by zero Traceback (most recent call last): File "E:/pydev/異常處理裝飾器.py", line 37, in inner return func(*args, **kwargs) File "E:/pydev/異常處理裝飾器.py", line 134, in four w = 1 / 0 EXCEPTION captured at function pro ZeroDivisionError: integer division or modulo by zero EXCEPTION captured at function five Traceback (most recent call last): EXCEPTION captured at function five File "E:/pydev/異常處理裝飾器.py", line 37, in inner EXCEPTION captured at function seven return func(*args, **kwargs) File "E:/pydev/異常處理裝飾器.py", line 115, in one w = 1 / 0 ZeroDivisionError: integer division or modulo by zero Traceback (most recent call last): File "E:/pydev/異常處理裝飾器.py", line 37, in inner return func(*args, **kwargs) File "E:/pydev/異常處理裝飾器.py", line 104, in five w = 1 / 0 ZeroDivisionError: integer division or modulo by zero Traceback (most recent call last): File "E:/pydev/異常處理裝飾器.py", line 37, in inner return func(*args, **kwargs) File "E:/pydev/異常處理裝飾器.py", line 148, in pro self.var = value / 0 ZeroDivisionError: integer division or modulo by zero 1 1 Traceback (most recent call last): File "E:/pydev/異常處理裝飾器.py", line 37, in inner return func(*args, **kwargs) File "E:/pydev/異常處理裝飾器.py", line 104, in five w = 1 / 0 ZeroDivisionError: integer division or modulo by zero Traceback (most recent call last): File "E:/pydev/異常處理裝飾器.py", line 37, in inner return func(*args, **kwargs) File "E:/pydev/異常處理裝飾器.py", line 37, in inner return func(*args, **kwargs) File "E:/pydev/異常處理裝飾器.py", line 104, in five w = 1 / 0 ZeroDivisionError: integer division or modulo by zero Traceback (most recent call last): File "E:/pydev/異常處理裝飾器.py", line 37, in inner return func(*args, **kwargs) File "E:/pydev/異常處理裝飾器.py", line 157, in seven return 1/0 ZeroDivisionError: integer division or modulo by zero c.eight被跳過(guò),所以沒(méi)有被里層捕獲,才會(huì)不打堆棧直接走到這里 最后這個(gè)會(huì)真正觸發(fā)異常,因?yàn)閙obj實(shí)例并沒(méi)有被裝飾過(guò) Traceback (most recent call last): File "E:/pydev/�쳣����װ����.py", line 212, in <module> m.five() File "E:/pydev/�쳣����װ����.py", line 104, in five w = 1 / 0 ZeroDivisionError: integer division or modulo by zero 進(jìn)程已結(jié)束,退出代碼 1
以上這篇Python類(lèi)中的裝飾器在當(dāng)前類(lèi)中的聲明與調(diào)用詳解就是小編分享給大家的全部?jī)?nèi)容了,希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
解讀requests.session()獲取Cookies全過(guò)程
這篇文章主要介紹了解讀requests.session()獲取Cookies全過(guò)程,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-02-02python如何實(shí)現(xiàn)wifi自動(dòng)連接,解決電腦wifi經(jīng)常斷開(kāi)問(wèn)題
這篇文章主要介紹了python實(shí)現(xiàn)wifi自動(dòng)連接,解決電腦wifi經(jīng)常斷開(kāi)的問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-06-06python編程羊車(chē)門(mén)問(wèn)題代碼示例
這篇文章主要介紹了python編程“羊車(chē)門(mén)”問(wèn)題代碼示例,初步接觸,僅供參考。不足之處,歡迎指出。2017-10-10NumPy數(shù)組創(chuàng)建方法與索引訪(fǎng)問(wèn)詳解
這篇文章主要介紹了NumPy數(shù)組創(chuàng)建方法與索引訪(fǎng)問(wèn),NumPy 中的核心數(shù)據(jù)結(jié)構(gòu)是 ndarray,它代表多維數(shù)組,NumPy 提供了多種方法來(lái)創(chuàng)建 ndarray 對(duì)象,文中通過(guò)代碼示例講解的非常詳細(xì),需要的朋友可以參考下2024-05-05python循環(huán)監(jiān)控遠(yuǎn)程端口的方法
這篇文章主要介紹了python循環(huán)監(jiān)控遠(yuǎn)程端口的方法,涉及Python實(shí)現(xiàn)端口監(jiān)控的技巧,需要的朋友可以參考下2015-03-03基于python實(shí)現(xiàn)的百度新歌榜、熱歌榜下載器(附代碼)
這篇文章主要介紹了基于python實(shí)現(xiàn)的百度新歌榜、熱歌榜下載器(附代碼),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-08-08對(duì)python判斷是否回文數(shù)的實(shí)例詳解
今天小編就為大家分享一篇對(duì)python判斷是否回文數(shù)的實(shí)例詳解,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2019-02-02詳解PANDAS 數(shù)據(jù)合并與重塑(join/merge篇)
這篇文章主要介紹了詳解PANDAS 數(shù)據(jù)合并與重塑(join/merge篇),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-07-07Python實(shí)現(xiàn)Kerberos用戶(hù)的增刪改查操作
這篇文章主要介紹了Python實(shí)現(xiàn)Kerberos用戶(hù)的增刪改查操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-12-12