I have been using a GUI library that allows you to connect signals to signal handlers using a connect function, for example:
widget.connect(signal, callback
A relatively simple solution to this is possible. We begin by using the decorator to mark the function. When instances are constructed, we search for these marks and register the callbacks.
More specifically, the mark and recapture pattern works by using the decorator to mark the function before it is bound, and then find it amongst the bound methods of the instance in the constructor.
First we use a decorator to do the marking (we use a set to allow for multiple marks on one method):
def callback(*args):
def decorate(f):
try:
f._marks.add(args)
except AttributeError:
f._marks = {args}
return f
return decorate
Then we use the inspect module to find the bound versions of the marked functions, and connect them:
def connect_callbacks(obj):
for _, f in inspect.getmembers(obj, inspect.ismethod):
try:
marks = f.__func__._marks
except AttributeError:
continue
for widget, signal in marks:
widget.connect(signal, f)
__func__
is the name of the original, unbound function. This allows us to access the marks that we applied earlier, facilitating our recapture.
We can then simply create our class and decorate our functions, remembering to connect our callbacks in the constructor:
class Test:
def __init__(self):
...
connect_callbacks(self)
@callback(widget, signal)
def test():
...
This allows us to connect the bound methods with a decorator.
Edit: I have published a tiny library on github that does this for you - it's called recap.