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

Is it possible to create a decorator inside a class?

或者您可以想出一个替代解决方案来解决我正在尝试做的事情。基本上我有一个 class 和一堆函数,我想将它们包装在 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 块?

我不确定您是否可以在您建议的性质中的 class 中使用装饰器。我认为这与装饰器本身的目的是违反直觉的(可以说是 hack)。

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

确实可以在 class 中创建装饰器,但您的实现有问题:

首先,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.

其次,您从装饰器 return 得到的内部包装函数至少需要将 self 作为参数并将其传递给 func,作为您将要使用的函数装饰期望 self 作为他们的第一个参数。

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


不过,我的建议是改为实施 context manager 并让它执行您的清理工作。对于你只是包含一组语句的情况,这更符合 Pythonic,如果你正确地实现它,你实际上也可以将它用作装饰器。