【问题标题】:How to store callback methods?如何存储回调方法?
【发布时间】:2009-11-04 12:25:47
【问题描述】:

我正在尝试存储一些方法回调,但引用它会使绑定的对象保持活动状态,所以我尝试为方法保留一个弱引用,但这似乎不可能?

所以

  • 为什么我不能保留一个弱参考。 to 方法(参见下面的示例)

  • 保持方法引用的最佳方式是什么?标准库中有什么东西吗?否则我将不得不保留函数和对象引用。分开?

示例:

import weakref

class A(object):
    def m(self): pass

a = A()

import weakref

class A(object):
    def m(self): pass

a = A()

rm = weakref.ref(a.m)
print "is weak ref to method dead?",rm() is None
print "Q1. why can't i keep weakref to bound method?"

ra = weakref.ref(a)
m = a.m
print "delete object"
del a
print "is object dead?",ra() is None
print "delete method"
del m
print "is object dead?",ra() is None
print "Q2. hmmm so i am stuck i can't keep a ref as it stops the object from gc, but weakref to method isn't working?"

【问题讨论】:

  • 简单地从回调列表中删除对象以删除引用有什么问题?为什么不写一个 callback.remove(method) 的“断开连接”方法?
  • 是的,这样做很好,但是当我存储回调时,我希望我可以弱引用它,这样如果有人忘记断开连接,它会自动断开连接,不会自动断开是一个更好的主意?
  • with 块以确保断开连接有什么问题?
  • 如果可以在所有情况下使用'with'没有问题,回调的目的是将来某个时间在某些事件中,某些对象中的某些回调将被调用,我该如何适应'with'在这里?

标签: python methods weak-references


【解决方案1】:

由于方法绑定到对象,如果对象不存在,你希望用它做什么?什么会自包含?

如果您不需要方法中的对象,请将其设为类方法。那么即使您对该方法有正常的引用,您的对象也将是 GC:d。

【讨论】:

  • 但在这种情况下对象确实存在,在示例中我直到结束才删除对象
  • 我确实想要对象,我的简单方法问题是“有没有办法保持回调,作为对象的弱引用,类似的东西
【解决方案2】:

Python Cookbook 中的配方 6.10,“保持对绑定方法的引用而不抑制垃圾回收”,提供了相当彻底但简洁的讨论和解决方案。您可以在线阅读(在 Google 图书上)here;我们将这个食谱归功于 Knapka、Jolliton 和 Nicodemus(部分来自另一个答案已经提到的原始 activestate 食谱食谱)当然,就像食谱中的往常一样,我们(我、我的妻子 Anna 和 David Ascher)是负责整个讨论流程和选择打印的确切代码版本的人,所以,如果这些有问题,那是 我们的 错;-)。

【讨论】:

  • +1 供你回答 :),顺便说一句,为什么 weakref.ref 不适用于绑定方法?
  • @Anurag,它按预期工作:它使对绑定方法对象的引用变弱!因此,由于没有对该绑定方法对象的 strong 引用,因此该对象立即“噗嗤”一声——正如我已经指出的讨论所解释的那样。
【解决方案3】:

我已经问过the same question here!在我的问题中,我谈到了 GObject,但认识到它在任何类型的 Python 中都是一个普遍问题!我在那里得到了 lioro 的帮助,我在当前代码中使用的内容如下。一些要点:

  • 您不能对方法对象进行弱引用。您必须弱引用实例及其函数属性,或者只是方法名称(就像我在下面的代码中所做的那样)

  • 您可以添加一些机制以在您连接的对象消失时取消注册回调,如果您不这样做,您将继续使用 Wea​​kCallback 对象,并在事件发生时执行一个空方法。

.

class WeakCallback (object):
    """A Weak Callback object that will keep a reference to
    the connecting object with weakref semantics.

    This allows object A to pass a callback method to object S,
    without object S keeping A alive.
    """
    def __init__(self, mcallback):
        """Create a new Weak Callback calling the method @mcallback"""
        obj = mcallback.im_self
        attr = mcallback.im_func.__name__
        self.wref = weakref.ref(obj, self.object_deleted)
        self.callback_attr = attr
        self.token = None

    def __call__(self, *args, **kwargs):
        obj = self.wref()
        if obj:
            attr = getattr(obj, self.callback_attr)
            attr(*args, **kwargs)
        else:
            self.default_callback(*args, **kwargs)

    def default_callback(self, *args, **kwargs):
        """Called instead of callback when expired"""
        pass

    def object_deleted(self, wref):
        """Called when callback expires"""
        pass

使用说明:

# illustration how I typically use it
weak_call = WeakCallback(self._something_changed)
long_lived_object.connect("on_change", weak_call)

我在子类中使用WeakCallback.token 属性来管理当连接器消失时断开回调的连接

【讨论】:

  • 许多其他人都有类似解决方案的指针,但我选择了这个作为页面内
【解决方案4】:

他们有一个很好的解决方案:

http://code.activestate.com/recipes/81253/

看看最后一个例子,由 Anonymous 发布。

【讨论】:

    猜你喜欢
    • 2023-03-22
    • 2016-03-21
    • 2011-01-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-30
    相关资源
    最近更新 更多