哪些 Python 包提供独立的事件系统?

新手上路,请多包涵

我知道 pydispatcher ,但 Python 周围肯定还有其他与事件相关的包。

哪些图书馆可用?

我对属于大型框架的事件管理器不感兴趣,我宁愿使用可以轻松扩展的小型准系统解决方案。

原文由 Josip 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 808
2 个回答

PyPI 包

截至 2022 年 10 月,这些是 PyPI 上可用的事件相关包,按最近的发布日期排序。

还有更多

有很多库可供选择,使用非常不同的术语(事件、信号、处理程序、方法分派、挂钩……)。

我试图对上述软件包以及此处的答案中提到的技术进行概述。

首先,一些术语…

观察者模式

事件系统最基本的样式是“处理程序方法包”,它是 观察者模式 的简单实现。

基本上,处理程序方法(可调用对象)存储在一个数组中,并在事件“触发”时调用每个方法。

发布-订阅

观察者事件系统的缺点是您只能在实际事件对象(或处理程序列表)上注册处理程序。所以在注册时,该事件已经存在。

这就是存在第二种事件系统样式的原因: 发布-订阅模式。在这里,处理程序不在事件对象(或处理程序列表)上注册,而是在中央调度程序上注册。此外,通知者只与调度员交谈。收听什么,或者发布什么,是由“signal”决定的,无非就是一个名字(字符串)。

中介者模式

可能也很有趣: 中介者模式

挂钩

“挂钩”系统通常用于应用程序插件的上下文中。该应用程序包含固定的集成点(挂钩),每个插件都可以连接到该挂钩并执行某些操作。

其他“事件”

注意: threading.Event 不是上述意义上的“事件系统”。这是一个线程同步系统,其中一个线程等待另一个线程向 Event 对象发出“信号”。

网络消息传递库也经常使用术语“事件”;有时这些在概念上是相似的;有时不是。它们当然可以跨越线程、进程和计算机的边界。参见例如 pyzmqpymqTwistedTornadogeventeventlet

弱引用

在 Python 中,持有对方法或对象的引用可确保它不会被垃圾收集器删除。这可能是可取的,但它也可能导致内存泄漏:链接的处理程序永远不会被清理。

一些事件系统使用弱引用而不是常规引用来解决这个问题。

关于各种图书馆的一些话

观察者式事件系统:

  • zope.event 展示了它如何工作的基本框架(参见 Lennart 的回答)。注意:此示例甚至不支持处理程序参数。
  • LongPoke 的“可调用列表” 实现表明,这样的事件系统可以通过子类化非常简单地实现 list
  • Felk 的变体 EventHook 也确保了被调用者和调用者的签名。
  • spassig 的 EventHook (Michael Foord 的事件模式)是一个简单的实现。
  • Josip 的 Valued Lessons Event 类 基本相同,但使用 set 而不是 list 来存储包,并实现 __call__ 都是合理的加法。
  • PyNotify 在概念上类似,也提供了变量和条件(’变量更改事件’)的额外概念。主页不起作用。
  • axel 基本上是一个 bag-of-handlers,具有更多与线程相关的功能,错误处理,……
  • python-dispatch 需要偶数源类派生自 pydispatch.Dispatcher
  • buslane 是基于类的,支持单个或多个处理程序并促进广泛的类型提示。
  • Pithikos 的 Observer/Event 是一种轻量级的设计。

发布订阅库:

  • blinker 有一些漂亮的功能,例如自动断开连接和基于发件人的过滤。
  • PyPubSub 是一个稳定的包,并承诺“有助于调试和维护主题和消息的高级功能”。
  • pymitter 是 Node.js EventEmitter2 的 Python 端口,提供命名空间、通配符和 TTL。
  • PyDispatcher 似乎强调多对多发布等方面的灵活性。支持弱引用。
  • louie 是一个重新设计的 PyDispatcher 并且应该“在各种各样的环境中”工作。
  • pypydispatcher 基于(你猜对了……)PyDispatcher,也适用于 PyPy。
  • django.dispatch 是重写的 PyDispatcher,“接口更有限,但性能更高”。
  • pyeventdispatcher 基于 PHP 的 Symfony 框架的事件分发器。
  • dispatcher 是从 django.dispatch 中提取出来的,但是已经相当老了。
  • Cristian Garcia 的 EventManger 是一个非常简短的实现。

其他:

  • pluggy 包含一个钩子系统,它被 pytest 插件使用。
  • RxPy3 实现了 Observable 模式并允许合并事件、重试等。
  • Qt 的信号和槽可从 PyQtPySide2 获得。它们在同一个线程中使用时用作回调,或者在两个不同线程之间用作事件(使用事件循环)。信号和槽的局限性在于它们仅适用于派生自 QObject 的类的对象。

原文由 florisla 发布,翻译遵循 CC BY-SA 4.0 许可协议

我一直这样做:

 class Event(list):
    """Event subscription.

    A list of callable objects. Calling an instance of this will cause a
    call to each item in the list in ascending order by index.

    Example Usage:
    >>> def f(x):
    ...     print 'f(%s)' % x
    >>> def g(x):
    ...     print 'g(%s)' % x
    >>> e = Event()
    >>> e()
    >>> e.append(f)
    >>> e(123)
    f(123)
    >>> e.remove(f)
    >>> e()
    >>> e += (f, g)
    >>> e(10)
    f(10)
    g(10)
    >>> del e[0]
    >>> e(2)
    g(2)

    """
    def __call__(self, *args, **kwargs):
        for f in self:
            f(*args, **kwargs)

    def __repr__(self):
        return "Event(%s)" % list.__repr__(self)

然而,就像我见过的其他所有东西一样,没有为此自动生成的 pydoc,也没有签名,这真的很糟糕。

原文由 L̲̳o̲̳̳n̲̳̳g̲̳̳p̲̳o̲̳̳k̲̳̳e̲̳̳ 发布,翻译遵循 CC BY-SA 2.5 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题
logo
Stack Overflow 翻译
子站问答
访问
宣传栏