或者你可以想出一个替代方案来解决我正在尝试做的事情。基本上,我有一个类,有一堆函数,我想在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块放在每个函数的内部?
确实可以在类中创建装饰器,但是您的实现是错误的:
首先,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
实例本身,这可能是你不想要的)。
但是,我的建议是实现一个上下文管理器,并让它执行清理。对于你只是封闭一组语句的情况,这是更python化的,如果你正确实现它,你实际上也可以将它用作装饰器。
我不确定您是否可以在您建议的性质中在类中使用装饰器。我认为这与装饰器本身的目的是反直觉的(可以说是一种hack)。
try-except块有什么问题?您已经将所有的清理代码放在一个函数中,因此遵循了DRY原则。装饰器和/或包装器只会限制错误处理的灵活性,因为它修复了try-except语句包装了整个函数,而没有提供任何实际的附加好处。