在 python 中实现观察者模式的替代方法

alternate ways to implement observer pattern in python

我正在研究 post post 关于如何在 python 中实现观察者模式。在同一个 post 上有这些评论。

1) In python you may as well just use plain functions, the ‘Observer’ class isnt really needed.

2) This is great example of what Java programmers are trying to do once they switch to Python – they feel like Python is missing all that crap and try to “port” it.

这些评论暗示观察者模式在 python 中并不是很有用,还有其他方法可以达到同样的效果。这是真的吗?如何才能做到?

观察者模式代码如下:

class Observable(object):

    def __init__(self):
        self.observers = []

    def register(self, observer):
        if not observer in self.observers:
            self.observers.append(observer)

    def unregister(self, observer):
        if observer in self.observers:
            self.observers.remove(observer)

    def unregister_all(self):
        if self.observers:
            del self.observers[:]

    def update_observers(self, *args, **kwargs):
        for observer in self.observers:
            observer.update(*args, **kwargs)

from abc import ABCMeta, abstractmethod

class Observer(object):
    __metaclass__ = ABCMeta

    @abstractmethod
    def update(self, *args, **kwargs):
        pass

class AmericanStockMarket(Observer):
    def update(self, *args, **kwargs):
        print("American stock market received: {0}\n{1}".format(args, kwargs))

class EuropeanStockMarket(Observer):
    def update(self, *args, **kwargs):
        print("European stock market received: {0}\n{1}".format(args, kwargs))


if __name__ == "__main__":
    observable = Observable()

    american_observer = AmericanStockMarket()
    observable.register(american_observer)

    european_observer = EuropeanStockMarket()
    observable.register(european_observer)

    observable.update_observers('Market Rally', something='Hello World')

您可以通过多种不同的方式 "observe" python 中的内容。使用 属性 descriptors, custom __setattr__, decorators...

这里是一个使用first class functions的简单例子:

class Foo(object):
    def __init__(self):
        self.observers = []

    def register(self, fn):
        self.observers.append(fn)
        return fn   # <-- See comments below answer

    def notify_observers(self, *args, **kwargs):
        for fn in self.observers:
            fn(*args, **kwargs)

然后您可以注册任何可调用项。

class Bar(object):
    def do_something(self, *args, **kwargs):
        pass # do something

foo = Foo()
bar = Bar()
foo.register(bar.do_something)

这将正常工作。对 do_something 的调用将具有正确的 self 值。因为对象的方法是可调用对象,它们带有对它们绑定到的实例的引用。

这可能有助于理解它的工作原理:

>>> bar
<Bar object at 0x7f3fec4a5a58>
>>> bar.do_something
<bound method Bar.do_something of <Bar object at 0x7f3fec4a5a58>>
>>> type(bar.do_something)
<class 'method'>
>>> bar.do_something.__self__
<Bar object at 0x7f3fec4a5a58>

[编辑:装饰器示例]

你也可以使用我们上面定义的register方法作为装饰器,像这样:

foo = Foo()

@foo.register
def do_something(*args, **kwargs):
    pass # do something

为此,请记住 register 需要 return 它注册的可调用对象。