【问题标题】:"outsourcing" exception-handling to a decorator [closed]“外包”异常处理给装饰者[关闭]
【发布时间】:2012-03-27 16:03:35
【问题描述】:

许多 try/except/finally 子句不仅“丑化”了我的代码,而且我发现自己经常对类似任务使用相同的异常处理。所以我正在考虑通过将它们“外包”给......装饰者来减少冗余。

因为我确定不是第一个得出这个结论的人,所以我在 Google 上搜索并发现了这个 - 恕我直言 - 巧妙的 recipe,它增加了处理多个异常的可能性。

但我很惊讶为什么这本身似乎并不是一种广为人知和使用的做法,所以我想知道是否有一个方面我没有考虑?

  1. 使用装饰器模式进行异常处理是假的还是我一直都错过了它?请赐教!有哪些陷阱?

  2. 是否有一个包/模块支持以合理的方式创建此类异常处理?

【问题讨论】:

  • 我正在查看答案,我只是想...如果您要将许多类似的错误处理任务一起重构为一个函数...您不只是创建了一个起点无论如何,对于装饰器中的类方法?
  • 我无法关注你,抱歉。你的意思是,我应该使用装饰器方法并使用新创建的异常装饰器类重构现有代码,还是你的意思是我不需要装饰器,因为我可以使用每个类的异常处理方法?跨度>
  • 我的意思是,如果您将大多数错误处理的细节抽象到一个方法中,那么您已经完成了将 那个 抽象为一个类,用作装饰器。我的想法?它可能偶尔会搞砸你的工作,但为了处理一般错误处理任务之外的事件,你总是可以,你知道的,在方法中编写内联 try:except 块。
  • 所以你赞成装饰器方法,只要它解决一般的异常处理,比如在放弃之前重试连接服务器几次?
  • 是的。我真的很喜欢 Ethan 的回答让你的方法看起来多么清晰。很聪明。

标签: python exception-handling decorator python-2.6


【解决方案1】:

在代码本身中保留 try/except/finally 块的最大原因是错误恢复通常是函数的一个组成部分。

例如,如果我们有自己的int() 函数:

def MyInt(text):
    return int(text)

text不能转换怎么办?返回0?返回None?

如果你有很多简单的情况,那么我可以看到一个简单的装饰器很有用,但我认为你链接到的配方试图做太多事情:它允许为每个可能的异常激活不同的功能——在这种情况下作为那些(几个不同的例外,几个不同的代码路径)我会推荐一个专用的包装函数。

这是我对简单装饰器方法的看法:

class ConvertExceptions(object):

    func = None

    def __init__(self, exceptions, replacement=None):
        self.exceptions = exceptions
        self.replacement = replacement

    def __call__(self, *args, **kwargs):
        if self.func is None:
            self.func = args[0]
            return self
        try:
            return self.func(*args, **kwargs)
        except self.exceptions:
            return self.replacement

和示例用法:

@ConvertExceptions(ValueError, 0)
def my_int(value):
    return int(value)

print my_int('34')      # prints 34
print my_int('one')     # prints 0

【讨论】:

    【解决方案2】:

    基本上,缺点是您不再需要决定如何在调用上下文中处理异常(只是让异常传播)。在某些情况下,这可能会导致缺乏责任分离。

    【讨论】:

    • 我不能通过使用单独的处理程序方法来解决参与者/反应器的耦合问题吗?我什至可以在每个受影响的类中定义一个类方法。
    • 你需要你的装饰器能够挂钩调用者提供的处理程序,此时你只是增加了复杂性,可能没有真正的收获(除非你的程序做了一个难以置信的大大量的异常处理通常归结为几种常见的形式,即便如此,也几乎可以肯定会有更智能的重构)。
    【解决方案3】:
    1. Python 中的装饰器与装饰器模式不同,认为有一些相似之处。您在这里的意思并不完全清楚,但我认为您的意思是来自 Python 的那个(因此,最好不要使用模式这个词)

    2. Python 中的装饰器对于异常处理不是很有用,因为您需要将一些上下文传递给装饰器。也就是说,您要么传递全局上下文,要么将函数定义隐藏在某个外部上下文中,我想说,这需要类似 LISP 的思维方式。

    3. 您可以使用上下文管理器来代替装饰器。我确实将它们用于此目的。

    【讨论】:

    • 上下文管理器绝对有用,但它们不能处理 OP 所说的情况:将异常处理代码与函数绑定而不在函数中。
    • 没错!伊森一下子就搞定了。我也在考虑上下文方法,但使用装饰器我有一种更通用的方法来解决冗余问题。
    • 我发现装饰器对异常翻译很有用——那么你就不需要那么多上下文了
    猜你喜欢
    • 2020-01-10
    • 1970-01-01
    • 2016-12-14
    • 1970-01-01
    • 2017-09-20
    • 1970-01-01
    • 1970-01-01
    • 2011-12-01
    相关资源
    最近更新 更多