我正试图定义一个装饰器以便执行一个类方法,先尝试一下,如果检测到错误,请将其提出来,说明失败的方法,以便用户可以看到错误是在哪个方法中。
在这里,我展示了我的代码的MRE(最小、可复制示例(。
from functools import wraps
def trier(func):
"""Decorator for trying A-class methods"""
@wraps(func)
def inner_func(self, name, *args):
try:
func(self, *args)
except:
print(f"An error apeared while {name}")
return inner_func
class A:
def __init__(self):
self._animals = 2
self._humans = 5
@trier('getting animals')
def animals(self, num):
return self._animals + num
@trier('getting humans')
def humans(self):
return self._humans
A().animals
许多错误正在引发,如:
TypeError:inner_func((缺少1个必需的位置参数:"name">
或误解了具有自函数的自类。
作为Stefan答案的替代方案,下面简单地使用不带任何参数的@trier
来装饰函数,然后在打印出错误消息时,我们可以使用func.__name__
来获得名称。
from functools import wraps
def trier(func):
"""Decorator for trying A-class methods"""
@wraps(func)
def inner_func(self, *args, **kwargs):
try:
return func(self, *args, **kwargs)
except:
print(f"An error apeared in {func.__name__}")
return inner_func
class A:
def __init__(self):
self._animals = 2
self._humans = 5
@trier
def animals(self, num):
return self._animals + num
@trier
def humans(self):
return self._humans
print(A().animals(1))
我还修复了代码中的几个错误:在trier
的尝试中,调用func
的结果从未返回,您需要在*args
之外还包括**kwargs
,以便使用命名参数。即A().animals(num=1)
仅在处理kwargs
时有效。
对于带参数的装饰器,您需要多一个嵌套级别:
from functools import wraps
def trier(name):
def wrapper(func):
@wraps(func)
def inner(*args, **kwargs):
try:
return func(*args, **kwargs)
except:
print(f"An error apeared while executing {name!r}")
return inner
return wrapper
class A:
def __init__(self):
self._animals = 2
self._humans = 5
@trier('getting animals')
def animals(self, num):
return self._animals + num
@trier('getting humans')
def humans(self):
return self._hoomans # wrong attribute name
a = A()
a.humans() # An error apeared while executing 'getting humans'
我会这样做,希望它能有所帮助。
from functools import wraps
import sys
def trier(func):
"""Decorator for trying A-class methods"""
@wraps(func)
def inner_func(self, *args, **kwargs):
print(f'Calling {func.__name__}')
try:
func(self, *args, **kwargs)
except:
print(f"An error apeared on function : {func.__name__}")
e = sys.exc_info()[2]
raise Exception(f"Exception occured on line: {e.tb_next.tb_lineno}")
return inner_func
class A:
def __init__(self):
self._animals = 2
self._humans = 5
@trier
def get_animals(self, num):
return self._animals + num
@trier
def get_humans(self):
return self._humans
@trier
def function_raising_exception(self):
raise Exception('This is some exception')
if __name__ == "__main__":
a = A()
a.get_animals(2)
a.function_raising_exception()
使用e = sys.exc_info()[2]
,您还可以获得回溯消息,并指向发生异常的行。
值得注意的是,在编写装饰器时,它应该适用于您在应用程序中使用的其他函数。