【问题标题】:how to properly implement Observer in python when the observer is [should be] destroyed当观察者[应该]被销毁时如何在python中正确实现观察者
【发布时间】:2017-04-06 01:47:18
【问题描述】:

我正在 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 在某些 Observable 对象的观察者列表中,则永远不会调用 Observer.__del__

请注意,我不一定要显式销毁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

【问题讨论】:

  • 你看过weakrefs吗?弱引用旨在解决这个问题,并且自 2.4 以来一直是 Python 的一个特性。

标签: python observer-pattern reference-cycle


【解决方案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)

【讨论】:

    【解决方案2】:

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

    【讨论】:

      猜你喜欢
      • 2012-05-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-05-12
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多