【发布时间】:2011-07-20 16:02:25
【问题描述】:
我在观察者模式中使用弱引用并注意到一个有趣的现象。如果我创建一个对象并将其中一个方法添加为 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