“外包”异常处理给装饰者

时间:2022-03-26 20:40:35

Many try/except/finally-clauses not only "uglify" my code, but i find myself often using identical exception-handling for similar tasks. So i was considering reducing redundancy by "outsourcing" them to a ... decorator.

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

Because i was sure not to be the 1st one to come to this conclusion, I googled and found this - imho - ingenious recipe which added the possibility to handle more than one exception.

因为我肯定不是第一个得出这个结论的人,所以我用Google搜索并发现了这个 - imho - 巧妙的配方,增加了处理多个例外的可能性。

But i was surprised why this doesn't seem to be a wide known and used practice per se, so i was wondering if there is maybe an aspect i wasn't considering?

但我很惊讶为什么这似乎不是一个广为人知的习惯本身,所以我想知道是否有一个方面我没有考虑?

  1. Is it bogus to use the decorator pattern for exception-handling or did i just miss it the whole time? Please enlighten me! What are the pitfalls?

    使用装饰器模式进行异常处理是假的还是我一直都想念它?请赐教!有什么陷阱?

  2. Is there maybe even a package/module out there which supports the creation of such exception-handling in a reasonable way?

    甚至可能有一个包/模块支持以合理的方式创建这样的异常处理?

3 个解决方案

#1


20  

The biggest reason to keep the try/except/finally blocks in the code itself is that error recovery is usually an integral part of the function.

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

For example, if we had our own int() function:

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

def MyInt(text):
    return int(text)

What should we do if text cannot be converted? Return 0? Return None?

如果文本无法转换,我们该怎么办?返回0?没有回报?

If you have many simple cases then I can see a simple decorator being useful, but I think the recipe you linked to tries to do too much: it allows a different function to be activated for each possible exception--in cases such as those (several different exceptions, several different code paths) I would recommend a dedicated wrapper function.

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

Here's my take on a simple decorator approach:

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

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

and sample usage:

和样品用法:

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

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

#2


4  

Basically, the drawback is that you no longer get to decide how to handle the exception in the calling context (by just letting the exception propagate). In some cases this may result in a lack of separation of responsibility.

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

#3


-1  

  1. Decorator in Python is not the same as the Decorator pattern, thought there is some similarity. It is not completely clear waht you mean here, but I think you mean the one from Python (thus, it is better not to use the word pattern)

    Python中的Decorator与Decorator模式不同,认为有一些相似之处。你在这里的意思并不完全清楚,但我认为你的意思是来自Python的那个(因此,最好不要使用单词模式)

  2. Decorators from Python are not that useful for exception handling, because you would need to pass some context to the decorator. That is, you would either pass a global context, or hide function definitions within some outer context, which requires, I would say, LISP-like way of thinking.

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

  3. Instead of decorators you can use contextmanagers. And I do use them for that purpose.

    您可以使用上下文管理器而不是装饰器。我确实将它们用于此目的。

#1


20  

The biggest reason to keep the try/except/finally blocks in the code itself is that error recovery is usually an integral part of the function.

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

For example, if we had our own int() function:

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

def MyInt(text):
    return int(text)

What should we do if text cannot be converted? Return 0? Return None?

如果文本无法转换,我们该怎么办?返回0?没有回报?

If you have many simple cases then I can see a simple decorator being useful, but I think the recipe you linked to tries to do too much: it allows a different function to be activated for each possible exception--in cases such as those (several different exceptions, several different code paths) I would recommend a dedicated wrapper function.

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

Here's my take on a simple decorator approach:

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

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

and sample usage:

和样品用法:

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

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

#2


4  

Basically, the drawback is that you no longer get to decide how to handle the exception in the calling context (by just letting the exception propagate). In some cases this may result in a lack of separation of responsibility.

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

#3


-1  

  1. Decorator in Python is not the same as the Decorator pattern, thought there is some similarity. It is not completely clear waht you mean here, but I think you mean the one from Python (thus, it is better not to use the word pattern)

    Python中的Decorator与Decorator模式不同,认为有一些相似之处。你在这里的意思并不完全清楚,但我认为你的意思是来自Python的那个(因此,最好不要使用单词模式)

  2. Decorators from Python are not that useful for exception handling, because you would need to pass some context to the decorator. That is, you would either pass a global context, or hide function definitions within some outer context, which requires, I would say, LISP-like way of thinking.

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

  3. Instead of decorators you can use contextmanagers. And I do use them for that purpose.

    您可以使用上下文管理器而不是装饰器。我确实将它们用于此目的。