如果[应该]销毁观察者,如何在python中正确实现Observer

ffe*_*rri 6 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)
Run Code Online (Sandbox Code Playgroud)

这是一个观察者:

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))
Run Code Online (Sandbox Code Playgroud)

代码按预期工作.

但是我需要将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)
Run Code Online (Sandbox Code Playgroud)

它有两个结果:

  • 如果self.foo.addObserver(self)没有注释掉,它打印foo changed from 23 to 44foo changed from 44 to 1
  • 如果self.foo.addObserver(self)被注释掉,它会打印出来Observer.__del__ called

Mik*_*ike 5

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