我在观察者模式中使用了弱点,并注意到一个有趣的现象。如果我创建一个对象并添加其中一个方法作为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已经死了。
答案 0 :(得分:3)
每当你引用一个对象方法时,就会发生一些魔法,这就是那种阻碍你的魔法。
具体来说,Python在对象的类上查找方法,然后将其与对象本身组合以创建一种称为绑定方法的可调用方法。每次例如计算表达式self.foo
,创建一个新的绑定方法实例。如果你立即对它进行弱化,那么就没有对绑定方法的其他引用(即使对象和类的方法都有实时引用)并且weakref会死掉。
请参阅this snippet on ActiveState了解解决方法。
答案 1 :(得分:1)
每次访问实例的方法obj.m
时,都会生成一个包装器(称为“绑定方法”),它可以调用并添加self
(obj
)作为第一个参数。调用。这是一个简洁的传递self
“隐式”的解决方案,并允许首先传递实例方法。但这也意味着每次键入obj.m
时,都会创建一个新的(非常轻量级)对象,除非你对它进行(非弱)引用,否则它将被GC,因为没有人会为你保持活力。