Python類中的裝飾器在當前類中的聲明與調(diào)用詳解
我的Python環(huán)境:3.7
在Python類里聲明一個裝飾器,并在這個類里調(diào)用這個裝飾器。
代碼如下:
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是在類Test中聲明并在其方法test_a中調(diào)用
2. 裝飾器test內(nèi)層wrapper函數(shù)的首參數(shù)是self
補充知識:python-類內(nèi)函數(shù)的全局裝飾器
有時,比如寫RF的測試庫的時候,很多方法都寫在一個類里。我們又可能需要一個通用的裝飾器,比如,要給某個底層類的方法打樁,查看入?yún)⒑统鰠?,用以理解業(yè)務(wù);或者要hold住所有的執(zhí)行錯誤,打印堆棧又不想程序退出或用例直接失敗
比如捕捉錯誤的裝飾器
import traceback
from functools import wraps
def trier(soft=False):
'''
:param bool soft: 為True時,打印報錯堆棧并忽略異常。默認False,打印報錯堆棧并拋出異常
:return:
如果要給類方法、靜態(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
這類裝飾器經(jīng)常會給類里的每個函數(shù)都使用
每次都裝飾的話,也挺麻煩
python里可以給類寫個裝飾器,所以可以輸入一個類,返回一個新類,這個新類擁有原來類里的所有方法,但所有方法都被裝飾
使用元類,可以做到這一點。
目前可以批量裝飾普通方法、靜態(tài)方法、類方法、屬性,暫不支持__init__和__del__之類的特殊方法,以免出現(xiàn)意外的問題。
目前類B使用了全局裝飾器,假如類B繼承自類A,類C繼承自類B
則類B、類C內(nèi)的所有方法都被全局裝飾(全局裝飾可以被繼承)
且類B繼承自類A的所有方法也會被全局裝飾
但這種裝飾不會影響到類A,調(diào)用類A下的方法時,所有方法都不被裝飾
經(jīng)過多次嘗試,最后的實現(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):
# 當對property類進行重組的時候,我們強制裝飾了property類的fget fset和fdel方法。但是,不是每個propery都有這三個方法,有些是None,強制裝飾會報錯,所以我們這里要考慮提前返回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提供了一個后門,被skipper裝飾的函數(shù)會跳過全局裝飾器
使用方法如下
@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é)果如圖

一個更完整的示例
from clswrapper那個文件 import skipper, classWrapper
import traceback
from functools import wraps
'''為簡潔起見,這次我們用的是不帶參數(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被跳過,所以沒有被里層捕獲,才會不打堆棧直接走到這里")
print("最后這個會真正觸發(fā)異常,因為mobj實例并沒有被裝飾過")
m=mobj()
time.sleep(1)
m.five()
它展示了這個強大裝飾器能處理的各種情況,執(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被跳過,所以沒有被里層捕獲,才會不打堆棧直接走到這里 最后這個會真正觸發(fā)異常,因為mobj實例并沒有被裝飾過 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 進程已結(jié)束,退出代碼 1
以上這篇Python類中的裝飾器在當前類中的聲明與調(diào)用詳解就是小編分享給大家的全部內(nèi)容了,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
python openpyxl 帶格式復(fù)制表格的實現(xiàn)
這篇文章主要介紹了python openpyxl 帶格式復(fù)制表格的實現(xiàn)操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2021-03-03
selenium+opencv實現(xiàn)滑塊驗證碼的登陸
很多網(wǎng)站登錄登陸時都要用到滑塊驗證碼,本文主要介紹了selenium+opencv實現(xiàn)滑塊驗證碼的登陸,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習或者工作具有一定的參考學(xué)習價值,需要的朋友們下面隨著小編來一起學(xué)習學(xué)習吧2023-04-04
selenium查找網(wǎng)頁出現(xiàn)加載卡頓或失敗的解決方法
這篇文章主要為大家詳細介紹了selenium查找網(wǎng)頁時如何處理網(wǎng)站資源一直加載非??D或者失敗的情況,文中的示例代碼講解詳細,感興趣的小伙伴可以了解一下2023-10-10

