0

或者,也许您可​​以想到我正在尝试做的替代解决方案。基本上,我有一个包含一堆函数的类,我想将它们包装在 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 块?

4

2 回答 2

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,因为您将要装饰的函数期望self作为它们的第一个参数。

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


然而,我的建议是实现一个上下文管理器并让它执行你的清理工作。对于只包含一组语句的情况,这更像是 Pythonic,如果你正确地实现它,你实际上也可以将它用作装饰器。

于 2015-10-14T18:10:12.980 回答
0

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

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

于 2015-10-14T17:00:44.800 回答