5

我正在浏览一篇关于如何在 python 中实现观察者模式的帖子。在同一个帖子上有这些评论。

1)在python中你也可以只使用普通函数,'Observer'类并不是真正需要的。

2) 这是 Java 程序员在切换到 Python 后尝试做的一个很好的例子——他们觉得 Python 缺少所有这些废话并尝试“移植”它。

这些评论暗示观察者模式在 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')
4

1 回答 1

7

您可以通过多种不同的方式在 python 中“观察”某些东西。使用属性描述符,自定义__setattr__装饰器......

这是一个使用一流函数的简单示例:

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需要返回它注册的可调用对象。

于 2017-06-12T12:47:44.603 回答