如何在 python 中连接到 GObject 信号,而不保留对连接器的引用? [英] How to connect to a GObject signal in python, without it keeping a reference to the connecter?

查看:35
本文介绍了如何在 python 中连接到 GObject 信号,而不保留对连接器的引用?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

The problem is basically this, in python's gobject and gtk bindings. Assume we have a class that binds to a signal when constructed:

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.

The problem is now that, no instance of ClipboardMonitor will ever die. The gtk clipboard is an application-wide object, and connecting to it keeps a reference to the object, since we use the callback self._clipboard_changed.

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

I'm debating how to work around this using weak references (weakref module), but I have yet to come up with a plan. Anyone have an idea how to pass a callback to the signal registration, and have it behave like a weak reference (if the signal callback is called when the ClipboardMonitor instance is out of scope, it should be a no-op).

补充:独立于 GObject 或 GTK+ 的措辞:

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

How do you provide a callback method to an opaque object, with weakref semantics? If the connecting object goes out of scope, it should be deleted and the callback should act as a no-op; the connectee should not hold a reference to the connector.

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

To clarify: I explicitly want to avoid having to call a "destructor/finalizer" method

推荐答案

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

The standard way is to disconnect the signal. This however needs to have a destructor-like method in your class, called explicitly by code which maintains your object. This is necessary, because otherwise you'll get circular dependency.

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)

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

As you pointed out, you need weakrefs if you want to avoid explicite destroying. I would write a weak callback factory, like:

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

(这是一个概念代码证明,对我有用——你可能应该根据你的需要调整这段代码).一些注意事项:

(this is a proof of concept code, works for me -- you should probably adapt this piece to your needs). Few notes:

  • 我分别存储回调对象和函数.你不能简单地创建一个绑定方法的弱引用,因为绑定方法是非常临时的对象.实际上weakref.ref(obj.method)会在创建weakref后立即销毁绑定的方法对象.我也没有检查是否需要为函数存储一个弱引用......我想如果你的代码是静态的,你可能可以避免这种情况.
  • 当对象包装器注意到弱引用不再存在时,它会将自身从信号发送者中移除.这对于破坏 CallbackWrapper 和信号发送者对象之间的循环依赖也是必要的.
  • I am storing callback object and function separatelly. You cannot simply make a weakref of a bound method, because bound methods are very temporary objects. Actually weakref.ref(obj.method) will destroy the bound method object instantly after creating a weakref. I didn't check whether it is needed to store a weakref to the function too... I guess if your code is static, you probably can avoid that.
  • The object wrapper will remove itself from the signal sender when it notices that the weak reference ceased to exist. This is also necessary to destroy the circular dependence between the CallbackWrapper and the signal sender object.

这篇关于如何在 python 中连接到 GObject 信号,而不保留对连接器的引用?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆