Python 可以在类中创建装饰器吗?

Python 可以在类中创建装饰器吗?,python,exception-handling,python-decorators,keyboardinterrupt,Python,Exception Handling,Python Decorators,Keyboardinterrupt,或者你可以想出一个替代方案来解决我的问题。基本上,我有一个类,它包含一系列函数,我想用try/except块来截获键盘中断错误,因为我有一个函数,可以整洁地清理我的每个函数 我想我可以创建一个decorator来实现这一点,但我遇到了一些问题。到目前为止,我有类似的东西 class MyClass: def catch_interrupt(self, func): def catcher(): try: func()

或者你可以想出一个替代方案来解决我的问题。基本上,我有一个类,它包含一系列函数,我想用try/except块来截获键盘中断错误,因为我有一个函数,可以整洁地清理我的每个函数

我想我可以创建一个decorator来实现这一点,但我遇到了一些问题。到目前为止,我有类似的东西

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块?

我不确定您是否可以在您建议的类中使用decorator。我认为这与装饰者本身的目的是背道而驰的(可以说是黑客)


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

确实可以在类内创建decorator,但您的实现有缺陷:

首先,
catch\u 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

@catch_interrupt
def my_func(self):
    # Start a long process that might need to be interrupted
其次,您从decorator返回的内部包装函数至少需要将
self
作为参数,并将其传递给
func
,因为您要装饰的函数期望
self
作为它们的第一个参数

您可能还需要调用内部装饰程序
\u catch\u interrupt
,以提示它是用于内部使用的。这不会阻止任何人调用它,但这是一个很好的做法,因为如果在类的实例上调用,行为将是不正确的(例如,
MyClass()。catch\u interrupt()
将尝试修饰
MyClass
实例本身,这可能是您不想要的)



然而,我的建议是实施一个新的程序,并让它执行您的清理。对于只包含一组语句的情况来说,这更像Python,如果实现正确,实际上也可以将其用作装饰器。

如果不传入self,我将如何调用我的End()函数?@programmeruntraordinair在上下文管理器中实现该行为,它们有一种方法,可以在保留上下文时自动清理,甚至可以使用参数来指示退出是由于成功完成还是引发异常。或者,如果您只想使用当前的装饰器,那么需要将
self
作为其第一个参数,这意味着您仍然可以访问它。