python - 如何在不保留对连接器的引用的情况下连接到 python 中的 GObject 信号?

标签 python pygtk pygobject

问题基本上是这样的,在 python 的 gobject 和 gtk 绑定(bind)中。假设我们有一个在构造时绑定(bind)到信号的类:

class ClipboardMonitor (object):
  def __init__(self):
    clip = gtk.clipboard_get(gtk.gdk.SELECTION_CLIPBOARD)
    clip.connect("owner-change", self._clipboard_changed)

现在的问题是,ClipboardMonitor 的任何实例都不会消亡。 gtk 剪贴板是一个应用程序范围的对象,连接到它会保留对该对象的引用,因为我们使用回调 self._clipboard_changed

我正在讨论如何使用弱引用(weakref 模块)来解决这个问题,但我还没有想出一个计划。任何人都知道如何将回调传递给信号注册,并使其表现得像弱引用(如果在 ClipboardMonitor 实例超出范围时调用信号回调,则它应该是空操作)。

添加:独立于 GObject 或 GTK+ 的措辞:

如何使用 weakref 语义为不透明对象提供回调方法?如果连接对象超出范围,则应将其删除并且回调应作为空操作; connectee 不应持有对连接器的引用。

澄清一下:我明确希望避免调用“析构函数/终结器”方法

最佳答案

标准的方式是断开信号。然而,这需要在您的类中有一个类似析构函数的方法,由维护您的对象的代码显式调用。这是必要的,否则您将获得循环依赖。

class ClipboardMonitor(object):
    [...]

    def __init__(self):
        self.clip = gtk.clipboard_get(gtk.gdk.SELECTION_CLIPBOARD)
        self.signal_id = self.clip.connect("owner-change", self._clipboard_changed)

    def close(self):
        self.clip.disconnect(self.signal_id)

正如您所指出的,如果您想避免显式破坏,则需要弱引用。我会写一个弱回调工厂,比如:

import weakref

class CallbackWrapper(object):
    def __init__(self, sender, callback):
        self.weak_obj = weakref.ref(callback.im_self)
        self.weak_fun = weakref.ref(callback.im_func)
        self.sender = sender
        self.handle = None

    def __call__(self, *things):
        obj = self.weak_obj()
        fun = self.weak_fun()
        if obj is not None and fun is not None:
            return fun(obj, *things)
        elif self.handle is not None:
            self.sender.disconnect(self.handle)
            self.handle = None
            self.sender = None

def weak_connect(sender, signal, callback):
    wrapper = CallbackWrapper(sender, callback)
    wrapper.handle = sender.connect(signal, wrapper)
    return wrapper

(这是一个概念验证代码,对我有用——您可能应该根据自己的需要调整这篇文章)。几点注意事项:

  • 我分别存储回调对象和函数。您不能简单地对绑定(bind)方法进行弱引用,因为绑定(bind)方法是非常临时的对象。实际上 weakref.ref(obj.method) 会在创建 weakref 后立即销毁绑定(bind)的方法对象。我没有检查是否也需要存储函数的弱引用...我想如果您的代码是静态的,您可能可以避免这种情况。
  • 当对象包装器注意到弱引用不复存在时,它会将自己从信号发送器中移除。这对于破坏 CallbackWrapper 和信号发送者对象之间的循环依赖也是必要的。

关于python - 如何在不保留对连接器的引用的情况下连接到 python 中的 GObject 信号?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1364923/

相关文章:

python - 是什么导致不同 GTK 版本之间的 GtkIconView 显示行为不同?

python - 检查一个数字是否是第二个数字的倍数

python - pip3 install pygobject错误: Nothing to do, gio无法找到并且是必需的

python - 在不知道变量数量的情况下插入 PostgreSQL 数据库,在 python 中

python - 对 pygtk3 的自省(introspection)可能吗?

python - 从 GTK 获取配色方案

python - 编写 Python GTK+ 应用程序的 'good practice' 方法是什么?

python - GTK 3 中的行删除按钮

Python 3 XML xml.etree 解析标准输出 bash cli 命令

python - 重新采样 OHLC 刻度数据并填补 Pandas 中的空白