小编gil*_*gil的帖子

异常传播装饰器是一个好的模式吗?

明确定义的自定义异常通常比内置异常提供更多信息;例如AgeError,超过ValueError。所以一般来说,我会尽可能使用前者。但因此,我的代码中散布着大量raise foo from bar样板文件,只是为了传播自定义异常。这是我的意思的一个例子。如果不使用自定义异常,我只需编写:

class Person:
    def set_age(self, age_as_string):
        self.age = int(age_as_string)
Run Code Online (Sandbox Code Playgroud)

这可能会引发TypeErrorValueError,但由于调用者会处理它,所以单行就可以了。

但要使用自定义异常,我需要样板:

class AgeError(Exception):
    pass

class Person:
    def set_age(self, age_as_string):
        try:
            self.age = int(age_as_string)
        except (TypeError, ValueError) as e:
            raise AgeError from e
Run Code Online (Sandbox Code Playgroud)

从调用者的角度来看,这提供了更多信息,但代码成本增加了 300%(仅计算方法体),并且模糊了set_age.

有没有办法两全其美?我尝试在谷歌上搜索解决方案,但即使这个问题似乎也没有得到太多讨论。我最终找到的解决方案是使用异常传播装饰器,由于其出色的功能,编写起来很简单contextlib(如果您需要手动实现它,则稍微不那么简单):

from contextlib import contextmanager

@contextmananer
def raise_from(to_catch, to_raise):
    try:
        yield
    except to_catch as e:
        raise to_raise from e
Run Code Online (Sandbox Code Playgroud)

现在我只需要额外一行,这不会掩盖业务逻辑,甚至使错误处理逻辑更加明显(而且看起来很聪明):

class Person:
    @raise_from(to_catch=(TypeError, ValueError), to_raise=AgeError)
    def set_age(self, age_as_string):
        self.age …
Run Code Online (Sandbox Code Playgroud)

python python-decorators

6
推荐指数
1
解决办法
94
查看次数

标签 统计

python ×1

python-decorators ×1