当观察者[应该]被摧毁时如何在python中正确实现Observer

时间:2016-11-22 11:41:29

标签: python observer-pattern reference-cycle

我在python中实现了一个观察者可观察的模式:

这是Observable类:

class Observable(object):
    def __init__(self, value):
        self.value = value
        self.observers = []

    def set(self, value):
        old = self.value
        self.value = value
        self.notifyObservers(old, self.value)

    def get(self):
        return self.value

    def addObserver(self, o):
        self.observers.append(o)

    def removeObserver(self, o):
        if o in self.observers:
            self.observers.remove(o)

    def notifyObservers(self, old, new):
        for o in self.observers:
            o.valueChanged(old, new)

这是观察者:

class Observer(object):
    def __init__(self, foo):
        self.foo = foo
        self.foo.addObserver(self)

    def __del__(self):
        print('Observer.__del__ called')
        self.foo.removeObserver(self)

    def valueChanged(self, old, new):
        print('foo changed from %s to %s' % (old, new))

代码按预期工作。

但是我需要销毁Observer(即当它被取消引用时,它应该从Observable对象中的观察者列表中删除。)

问题在于,如果Observer.__del__位于某个Observer对象的观察者列表中,那么Observable永远不会被调用。

请注意,我不一定明确地销毁Observer,因为变量赋值也会被取消引用,因此在销毁之前明确地调用removeObserver() 是不可行的

如果我发表评论self.foo.addObserver(self),则没有对Observer的其他引用,并且在其上调用del会调用Observer.__del__

此方案的测试用例是:

foo = Observable(23)
bar = Observer(foo)
foo.set(44)
bar = None
foo.set(1)

它有两个结果:

  • 如果self.foo.addObserver(self)未被注释掉,则会打印foo changed from 23 to 44foo changed from 44 to 1
  • 如果self.foo.addObserver(self)被注释掉,则会打印Observer.__del__ called

2 个答案:

答案 0 :(得分:5)

弱参考似乎可以解决您的问题。 您可以将观察者更改为管理weak-references,例如,替换list中的weakref.WeakKeyDictionary,或者实施其他弱引用容器。顺便说一下,使用散列类型(如字典)也会比列表更好,因为删除观察者会更有效率。

答案 1 :(得分:1)

解决方案:(将Observable.observers更改为weakref.WeakKeyDictionary

class Observable(object):
    def __init__(self, value):
        self.value = value
        self.observers = weakref.WeakKeyDictionary()

    def set(self, value):
        old = self.value
        self.value = value
        self.notifyObservers(old, self.value)

    def get(self):
        return self.value

    def addObserver(self, o):
        self.observers[o] = 1

    def removeObserver(self, o):
        del self.observers[o]

    def notifyObservers(self, old, new):
        for o in self.observers:
            o.valueChanged(old, new)

此外,不需要在观察者的析构函数中调用.removeObserver(self)