How to get a reference to an instance method from a decorator

后端 未结 1 568
遇见更好的自我
遇见更好的自我 2021-01-20 01:29

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         


        
1条回答
  •  傲寒
    傲寒 (楼主)
    2021-01-20 02:28

    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.

    0 讨论(0)
提交回复
热议问题