【问题标题】:alternate ways to implement observer pattern in python在 python 中实现观察者模式的替代方法
【发布时间】:2017-11-13 22:23:27
【问题描述】:

我正在阅读一篇关于如何在 python 中实现观察者模式的帖子post。在同一个帖子里有这些 cmets。

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

2) 这是 Java 程序员曾经尝试做的一个很好的例子 他们改用 Python——他们觉得 Python 缺少了所有这些废话 并尝试“移植”它。

这些 cmets 意味着观察者模式在 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')

【问题讨论】:

  • 您要解决什么问题?模式只是工具;试图“实施”它们在应用它们的特定上下文之外毫无意义。
  • @spectras 我正在尝试学习模式,因此我需要实现它。但是根据那些 cmets,这种模式在 python 中并不是很有用。并且存在替代方法来实现相同的想法
  • 模式本身很有用,但实现是 Java 风格的,因为您定义了一个“接口”Observer,它具有实现必须实现的方法,以便 Observable 然后可以调用那些实现的那个方法(更新)。在 python 中,您不妨将普通函数或绑定方法作为观察者传递,而无需所有样板。这并不是说你永远不应该这样做。 “接口”在 Python 中也有其用途。
  • 在 cmets 中提出的观点(应该持保留态度,这是真的……仅在一定程度上)是您不会像构建功能等效的 Java 代码。
  • 不强制执行任何东西,而是直接接受可调用对象而不是“观察者对象”。你甚至可以在 python 中传递绑定的方法。

标签: python observer-pattern first-class-functions


【解决方案1】:

您可以通过多种不同的方式在 python 中“观察”某些东西。使用属性descriptors、自定义__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 需要返回它注册的可调用对象。

【讨论】:

  • 如果 register() 返回 fn,它也可以作为装饰器工作,因此可以使用 @observable.register ... 函数。只是 Python 可能不同的一个小例子。
  • @IljaEverilä> 我担心这个答案太过分了,特别是考虑到它也是范式的变化(您需要在定义观察者方法之前存在可观察的实例,这会变得更远来自Java)。但这是完全正确的,我肯定会让它在现实世界的例子中返回可调用对象。我添加了带有注释的退货。
  • 我会对那个装饰器解决方案感兴趣。 ;) 我不是来自 Java,而是来自 C++。
  • @buhtz 你在这里。
  • 我不熟悉装饰器。 ;)
猜你喜欢
  • 2011-07-07
  • 1970-01-01
  • 2011-12-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-12-09
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多