Or maybe you can think of an alternative solution to what I'm trying to do. Basically I have a class with a bunch of functions that I want to wrap in try/except blocks to intercept the KeyboardInterrupt error as I have a function that tidily cleans up each of my functions.
Instead of putting huge try catch blocks in each function I figured I could create a decorator to do that, but I'm running into some issues. So far I have something like this
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()
The issue when I run this is that I get the error
TypeError: catch_interrupt() takes exactly 2 arguments (1 given)
Is this even possible? Is there a better way or should I really just put try/except blocks around each functions innards?
It is indeed possible to create a decorator inside a class, but your implementation is faulty:
First of all, catch_interrupt()
can't take self
.
@catch_interrupt
def my_func(self):
# Start a long process that might need to be interrupted
is equivalent to
def my_func(self):
# Start a long process that might need to be interrupted
my_func = catch_interrupt(my_func)
Obviously this doesn't allow self
.
Secondly, your inner wrapper function that you return from the decorator needs to at least take self
as an argument and pass it on to func
, as the functions you will be decorating expect self
as their first arguments.
You may also want to call your internal decorator _catch_interrupt
to hint that it's meant for internal usage. That won't prevent anyone from calling it, but it's good practice given the behavior will be incorrect if called on an instance of the class (e.g. MyClass().catch_interrupt()
will attempt to decorate the MyClass
instance itself, which you probably don't want).
My suggestion, however, would be to implement a context manager instead and have it perform your cleanup. That is more Pythonic for the cases where you're just enclosing a group of statements, and if you implement it right you can actually use it as a decorator too.