【问题标题】:How to get a reference to an instance method from a decorator如何从装饰器中获取对实例方法的引用
【发布时间】:2012-08-18 05:11:21
【问题描述】:

我一直在使用一个 GUI 库,它允许您使用连接函数将信号连接到信号处理程序,例如:

widget.connect(signal, callback)

意味着函数callback 将在小部件发出信号时运行。为了使我的代码更好,并从我的构造函数中删除一系列connect 调用,我决定使用一个效果很好的装饰器:

def callback(widget, signal)
    def decorate(f):
            widget.connect(signal, f)
            return f
    return decorate

...

@callback(widget, signal)
def do_something():
    ...

这非常有效,直到我需要在一个类中执行此操作 - 该函数在 绑定到该类之前被修饰,这意味着给定的回调函数不会获得该类的实例拥有它,让它变得无用。有没有办法让它工作?

【问题讨论】:

    标签: python callback signals decorator


    【解决方案1】:

    一个相对简单的解决方案是可能的。我们首先使用装饰器来标记函数。在构造实例时,我们会搜索这些标记并注册回调。

    更具体地说,标记和重新捕获模式的工作原理是使用装饰器在绑定函数之前对其进行标记,然后在构造函数中实例的绑定方法中找到它。

    首先我们使用装饰器进行标记(我们使用集合来允许在一个方法上进行多个标记):

    def callback(*args):
        def decorate(f):
            try:
                f._marks.add(args)
            except AttributeError:
                f._marks = {args}
            return f
        return decorate
    

    然后我们使用the inspect module找到标记函数的绑定版本,并将它们连接起来:

    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__ 是原始未绑定函数的名称。这使我们能够访问我们之前应用的标记,便于我们重新捕获

    然后我们可以简单地创建我们的类并装饰我们的函数,记住在构造函数中连接我们的回调:

    class Test:
        def __init__(self):
            ...
            connect_callbacks(self)
    
        @callback(widget, signal)
        def test():
            ...
    

    这允许我们将绑定的方法与装饰器连接起来。

    编辑:我在 github 上发布了一个小型库,可以为您执行此操作 - 它称为 recap

    【讨论】:

      猜你喜欢
      • 2019-02-03
      • 1970-01-01
      • 2019-01-03
      • 1970-01-01
      相关资源
      最近更新 更多