Skip to main content
 首页 » 编程设计

python之在 Python 的属性上使用装饰器处理异常

2025年05月04日25dyllove98

我有一个属性,它有一个断言来检查值是否为 str 类型。

为了捕获这个 assertionError,我根据我在网上找到的例子创建了一个装饰器。

装饰器:

def catch_assertionerror(function): 
    def handle_problems(*args, **kwargs): 
        try: 
            return function(*args, **kwargs) 
        except AssertionError: 
            # log_error(err.args[0]) 
            print "error caught" 
    return handle_problems 

属性:

@catch_assertionerror 
@name.setter 
def name(self, value): 
    assert isinstance(value, str), "This value should be a string" 
    self._name = name 

设置名称属性:

self.name = self.parse_name_from_xml() 

当我运行这段代码时,没有显示任何错误,所以我猜它被捕获了,但另一方面,错误消息并没有打印到屏幕上。

然后我尝试了一个我在 Stachoverflow 上找到的更简单的例子:

def handleError(function): 
    def handleProblems(): 
        try: 
            function() 
        except Exception: 
            print "Oh noes" 
    return handleProblems 
 
 
@handleError 
def example(): 
    raise Exception("Boom!") 

这也处理了错误,但没有将错误消息打印到屏幕上。

有人可以向我解释一下我在这里缺少什么吗?

请您参考如下方法:

你的后一个例子对我有用,但你的主要问题在于你没有用 catch_assertionerror 包装一个函数

@catch_assertionerror 
@name.setter 
def name(self, value): 
    assert isinstance(value, str), "This value should be a string" 
    self._name = name 

但是一个descriptor .更糟糕的是,您返回的是一个函数,而不是包装原始函数的新描述符。现在,当您分配给 name 属性时,您只需将包装函数替换为分配的值即可。

逐步使用您的原始类定义:

class X(object): 
 
    @property 
    def name(self): 
        return self._name 
 
    @catch_assertionerror 
    @name.setter 
    def name(self, value): 
        assert isinstance(value, str), "This value should be a string" 
        self._name = value 
 
>>> x = X() 
>>> x.name 
<unbound method X.handle_problems> 
>>> x.__dict__ 
{} 
>>> x.name = 2 
>>> x.name 
2 
>>> x.__dict__ 
{'name': 2} 

您必须做的是包装方法函数,然后将其传递给描述符处理装饰器:

class X(object): 
    @property 
    def name(self): 
        return self._name 
    @name.setter 
    @catch_assertionerror 
    def name(self, value): 
        assert isinstance(value, str), "This value should be a string" 
        self._name = value 

等等:

>>> x = X() 
>>> x.name 
Traceback (most recent call last): 
  File "<stdin>", line 1, in <module> 
  File "<stdin>", line 4, in name 
AttributeError: 'X' object has no attribute '_name' 
>>> x.name = 2 
error caught 
>>> x.name = "asdf" 
>>> x.name 
'asdf' 

将来考虑使用 functools.wraps 和 functools.update_wrapper。没有它们,您的类和函数将更难检查,因为您的包装器将隐藏原始的:

>>> @catch_assertionerror 
... def this_name_should_show(): pass 
...  
>>> this_name_should_show 
<function handle_problems at 0x7fd3d69e22a8> 

以这种方式定义装饰器:

def catch_assertionerror(function): 
    @wraps(function) 
    def handle_problems(*args, **kwargs): 
        ... 
    return handle_problems 

将保留原始函数的信息:

>>> @catch_assertionerror 
... def this_name_should_show(): pass 
...  
>>> this_name_should_show 
<function this_name_should_show at 0x7fd3d69e21b8> 

在您的情况下,它还会向您表明存在问题:

# When trying to define the class 
Traceback (most recent call last): 
  File "<stdin>", line 1, in <module> 
  File "<stdin>", line 6, in X 
  File "<stdin>", line 2, in catch_assertionerror 
  File "/usr/lib/python2.7/functools.py", line 33, in update_wrapper 
    setattr(wrapper, attr, getattr(wrapped, attr)) 
AttributeError: 'property' object has no attribute '__module__'