【问题标题】:why are my weakrefs dead in the water when they point to a method? [duplicate]为什么我的弱引用在指向方法时会死在水中? [复制]
【发布时间】:2011-07-20 16:02:25
【问题描述】:

可能重复:
Why doesn't the weakref work on this bound method?

我在观察者模式中使用弱引用并注意到一个有趣的现象。如果我创建一个对象并将其中一个方法添加为 Observable 的观察者,则该引用几乎立即失效。谁能解释发生了什么?

我也很想知道为什么这可能是个坏主意。我决定不使用weakrefs,只是确保使用Observable.removeobserver正确清理自己,但我的好奇心在这里杀死了我。

代码如下:

from weakref import ref
class Observable:
    __observers = None
    def addobserver(self, observer):
        if not self.__observers:
            self.__observers = []
        self.__observers.append(ref(observer))
        print 'ADDING observer', ref(observer)

    def removeobserver(self, observer):
        self.__observers.remove(ref(observer))

    def notify(self, event):
        for o in self.__observers:
            if o() is None:
                print 'observer was deleted (removing)', o
                self.__observers.remove(o)
            else:
                o()(event)

class C(Observable):
    def set(self, val):
        self.notify(val)

class bar(object):
    def __init__(self):
        self.c = C()
        self.c.addobserver(self.foo)
        print self.c._Observable__observers

    def foo(self, x):
        print 'callback', x  #never reached

b = bar()
b.c.set(3)

这是输出:

ADDING observer <weakref at 0xaf1570; to 'instancemethod' at 0xa106c0 (foo)>
[<weakref at 0xaf1570; dead>]
observer was deleted (removing) <weakref at 0xaf1570; dead>

主要需要注意的是调用addobserver之后的print语句显示weakref已经死了。

【问题讨论】:

  • 您是否意识到__observers 是一个类变量,因此在Observable 的所有实例之间共享(这包括子类)?此外,如果您正在使用名称修饰(恕我直言,您不应该这样做,但这是一个不同的主题),您不应该从外部访问经过修饰的名称。具体来说,你硬编码一个类名并访问你可能试图保持私有的东西。
  • 啊,所以我应该摆脱类 var 声明并使用 if "__observers" in self.__dict__ 而不是 if not self.__observers。对哦。差点错过了。另外,我知道私有变量应该保持私有,我只是出于演示目的打印它。不过,这整个名字修饰对我来说是新事物,所以感谢您为其命名(不是双关语),所以我可以用谷歌搜索它......我不确定为什么 __observers 被重命名为 _Observable__observers。我可能会称它为 _observers。
  • delnan:您对__observers 作为类变量的评论似乎并不完全正确。最初是这样,但是当调用addobserver 时,self.__observers = [] 会初始化实例变量。类变量仍然可以访问(并且仍然是None),但只能通过Observable._Observable__observers 访问。
  • delnan:看来您关于__observers 是类变量的评论并不完全正确。最初是这样,但是当调用addobserver 时,self.__observers = [] 会初始化实例变量。类变量仍然可以访问,但只能由 Observable._Observable__observers 访问。

标签: python weak-references observer-pattern


【解决方案1】:

每当您引用一个对象方法时,都会发生一些神奇的事情,而正是这种神奇的事情阻碍了您。

具体来说,Python 在对象的类上查找方法,然后将其与对象本身结合起来创建一种称为绑定方法的可调用对象。每次例如评估表达式self.foo,创建一个新的绑定方法实例。如果您立即对此进行弱引用,则没有其他对绑定方法的引用(即使对象和类的方法仍然具有活动引用)并且弱引用死亡。

请参阅this snippet on ActiveState 了解解决方法。

【讨论】:

    【解决方案2】:

    每次访问实例的方法obj.m 时,都会生成一个可调用的包装器(称为“绑定方法”),并在调用时添加self (obj) 作为第一个参数。这是一个“隐式”传递self 的巧妙解决方案,并允许首先传递实例方法。但这也意味着每次键入obj.m 时,都会创建一个新的(非常轻量级的)对象,除非您保留对它的(非弱)引用,否则它将被 GC'd,因为没有人会保留它为你而活。

    【讨论】:

      猜你喜欢
      • 2014-06-17
      • 2014-03-06
      • 1970-01-01
      • 2013-06-30
      • 2021-04-18
      • 1970-01-01
      • 2014-09-09
      • 2018-09-02
      • 1970-01-01
      相关资源
      最近更新 更多