python类装饰器详解-Python类中的装饰器在当前类中的声明与调用详解
我的Python环境:3.7
在Python类里声明一个装饰器,并在这个类里调用这个装饰器。
代码如下:
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} {b}')
注意:
1. 其中装饰器test是在类Test中声明并在其方法test_a中调用
2. 装饰器test内层wrapper函数的首参数是self
补充知识:python-类内函数的全局装饰器
有时,比如写RF的测试库的时候,很多方法都写在一个类里。我们又可能需要一个通用的装饰器,比如,要给某个底层类的方法打桩,查看入参和出参,用以理解业务;或者要hold住所有的执行错误,打印堆栈又不想程序退出或用例直接失败
比如捕捉错误的装饰器
import traceback
from functools import wraps
def trier(soft=False):
'''
:param bool soft: 为True时,打印报错堆栈并忽略异常。默认False,打印报错堆栈并抛出异常
:return:
如果要给类方法、静态方法装饰,则该装饰器必须处于比@staticmethod装饰器更内一层才行
'''
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
或者参数跟踪的装饰器
def tracer(func):
def infunc(*args, **kwargs):
print func.__name__, args, kwargs
res=infunc(*args, **kwargs)
print func.__name__, res
return res
这类装饰器经常会给类里的每个函数都使用
每次都装饰的话,也挺麻烦
python里可以给类写个装饰器,所以可以输入一个类,返回一个新类,这个新类拥有原来类里的所有方法,但所有方法都被装饰
使用元类,可以做到这一点。
目前可以批量装饰普通方法、静态方法、类方法、属性,暂不支持__init__和__del__之类的特殊方法,以免出现意外的问题。
目前类B使用了全局装饰器,假如类B继承自类A,类C继承自类B
则类B、类C内的所有方法都被全局装饰(全局装饰可以被继承)
且类B继承自类A的所有方法也会被全局装饰
但这种装饰不会影响到类A,调用类A下的方法时,所有方法都不被装饰
经过多次尝试,最后的实现代码如下
# 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装饰的函数会跳过全局装饰器
使用方法如下
@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()
执行结果如图
一个更完整的示例
from clswrapper那个文件 import skipper, classWrapper
import traceback
from functools import wraps
'''为简洁起见,这次我们用的是不带参数的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("最后这个会真正触发异常,因为mobj实例并没有被装饰过")
m=mobj()
time.sleep(1)
m.five()
它展示了这个强大装饰器能处理的各种情况,执行结果应该如下
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被跳过,所以没有被里层捕获,才会不打堆栈直接走到这里
最后这个会真正触发异常,因为mobj实例并没有被装饰过
Traceback (most recent call last):
File "E:/pydev/�쳣����װ����.py", line 212, in
m.five()
File "E:/pydev/�쳣����װ����.py", line 104, in five
w = 1 / 0
ZeroDivisionError: integer division or modulo by zero
进程已结束,退出代码 1
以上这篇Python类中的装饰器在当前类中的声明与调用详解就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持脚本之家。
python类装饰器详解-Python类中的装饰器在当前类中的声明与调用详解相关推荐
- python类装饰器详解-Python 装饰器详解
开放封闭原则: 开放对扩展 封闭修改源代码 改变了人家调用方式 装饰器结构 """ 默认结构为三层!!!每层返回下一层内存地址就可以进行执行函数, 传参:语法糖中的传参可 ...
- python类装饰器详解-python 中的装饰器详解
装饰器 闭包 闭包简单的来说就是一个函数,在该函数内部再定义一个函数,并且这个内部函数用到了外部变量(即是外部函数的参数),最终这个函数返回内部函数的引用,这就是闭包. def decorator(p ...
- python类装饰器详解-Python装饰器详解
python的装饰器其实是一个语法糖,第一行是@跟着一个表达式:第二行必须以def或者class起始(亦即函数或者class的定义). python的装饰器,必须是可调用的对象,而且必须是可以以一个参 ...
- python类装饰器详解-Python装饰器基础概念与用法详解
本文实例讲述了Python装饰器基础概念与用法.分享给大家供大家参考,具体如下: 装饰器基础 前面快速介绍了装饰器的语法,在这里,我们将深入装饰器内部工作机制,更详细更系统地介绍装饰器的内容,并学习自 ...
- python装饰器由浅入深_详解Python装饰器由浅入深
装饰器的功能在很多语言中都有,名字也不尽相同,其实它体现的是一种设计模式,强调的是开放封闭原则,更多的用于后期功能升级而不是编写新的代码.装饰器不光能装饰函数,也能装饰其他的对象,比如类,但通常,我们 ...
- python的装饰器迭代器与生成器_详解python中的生成器、迭代器、闭包、装饰器
迭代是访问集合元素的一种方式.迭代器是一个可以记住遍历的位置的对象.迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束.迭代器只能往前不会后退. 1|1可迭代对象 以直接作用于 for ...
- python装饰器详解-Python装饰器基础概念与用法详解
本文实例讲述了Python装饰器基础概念与用法.分享给大家供大家参考,具体如下: 装饰器基础 前面快速介绍了装饰器的语法,在这里,我们将深入装饰器内部工作机制,更详细更系统地介绍装饰器的内容,并学习自 ...
- 详解Python的装饰器
详解Python的装饰器 Python中的装饰器是你进入Python大门的一道坎,不管你跨不跨过去它都在那里. 为什么需要装饰器 我们假设你的程序实现了say_hello()和say_goodbye( ...
- python类的静态属性和静态方法_详解Python中的静态方法与类成员方法
前言 因为Python的水平目前一直是处于能用阶段,平时写的脚本使用的Python的写法也比较的简单,没有写过稍微大一点的项目.对Python中的类,类之间的组织关系,整个项目中类之间如何耦合还缺乏认 ...
最新文章
- Error:No suitable device found: no device found for connection “System eth1″
- ThreadPoolExecutor 的八种拒绝策略 | 含番外!
- NYOJ 559 报数游戏
- xaml修改后台代码的值_Django定制后台和修改模型
- HDU-2829 Lawrence (DP+四边形不等式优化)
- php中文切齿,PHP 各种函数
- 容器编排技术 -- kubectl Cheat Sheet
- JavaScript DOM编程艺术学习笔记(一)
- 《Effective C++》:条款46-条款47
- dateutils java_JAVA 日期处理工具类 DateUtils
- 单点登录原理及简单实现
- Javaweb重要知识点总结(六)常见的前端框架
- php抓取微信公众号文章 封面图,教你如何一键提取微信公众号文章的封面图
- html炫酷在线,html单页炫酷
- 试用 必应bing 缤纷桌面
- AI 研究助力体育分析
- 微信开启全民付费模式,我们有个共同好友叫“Feed广告”
- 【Redis】Redis介绍
- 【强化学习论文合集】二十九.2021国际机器学习大会论文(ICML2021)
- might和could的区别用法_地道的英语口语:Might、 may、could用法区分