是否可以在类中创建装饰器?

时间:2015-10-14 16:14:15

标签: python exception-handling python-decorators keyboardinterrupt

或许你可以想到我正在尝试做的另一种解决方案。基本上我有一个带有一堆函数的类,我想在try / except块中包装来拦截 KeyboardInterrupt 错误,因为我有一个整洁地清理我的每个函数的函数。

我没有在每个函数中放置巨大的try catch块,而是认为我可以创建一个装饰器来做到这一点,但我遇到了一些问题。到目前为止,我有类似的东西

class MyClass:
    def catch_interrupt(self, func):
        def catcher():
            try:
                func()
            except KeyboardInterrupt:
                self.End()
        return catcher

    @catch_interrupt
    def my_func(self):
        # Start a long process that might need to be interrupted

    def End(self):
        # Cleans up things
        sys.exit()

运行此问题时,我收到错误

TypeError: catch_interrupt() takes exactly 2 arguments (1 given)

这甚至可能吗?有没有更好的方法或者我应该在每个函数内部放置try / except块?

2 个答案:

答案 0 :(得分:2)

确实可以在类中创建一个装饰器,但是你的实现是错误的:

首先,catch_interrupt()无法取self

@catch_interrupt
def my_func(self):
    # Start a long process that might need to be interrupted

相当于

def my_func(self):
    # Start a long process that might need to be interrupted
my_func = catch_interrupt(my_func)

显然这不允许self

其次,从装饰器返回的内部包装函数至少需要将self作为参数并将其传递给func,因为您将要装饰的函数期望{{1作为他们的第一个参数。

您可能还想调用内部装饰器self来暗示它是用于内部使用的。这不会阻止任何人调用它,但是如果在类的实例上调用行为将是不正确的,这是很好的做法(例如_catch_interrupt将尝试装饰MyClass().catch_interrupt()实例本身,你可能不想要。)

然而,我的建议是实现context manager而是让它执行清理。对于你只是封闭一组语句的情况,这就更Pythonic了,如果你正确实现它,你实际上也可以将它用作装饰器。

答案 1 :(得分:0)

我不确定你是否可以在你提议的性质中使用类中的装饰器。我认为这对于装饰者本身的目的是违反直觉的(黑客,可以这么说)。

try-except块有什么问题?您已将所有清理代码放在一个函数中,因此遵守DRY原则。装饰器和/或包装器只会通过修复try-except语句包装整个函数来限制错误处理的灵活性,而不会提供任何真正的额外好处。