哪些Python库提供独立的事件系统?
我知道有一个叫做 pydispatcher 的东西,但Python里肯定还有其他和事件相关的库。
有哪些库可以用呢?
我对那些大框架里的事件管理器不感兴趣,我更想要一个简单的、基础的解决方案,这样我可以轻松地进行扩展。
16 个回答
我们使用了一个叫做EventHook的东西,这是Michael Foord在他的事件模式中提到的。
只需要在你的类里添加EventHooks,就可以了:
class MyBroadcaster()
def __init__():
self.onChange = EventHook()
theBroadcaster = MyBroadcaster()
# add a listener to the event
theBroadcaster.onChange += myFunction
# remove listener from the event
theBroadcaster.onChange -= myFunction
# fire event
theBroadcaster.onChange.fire()
我们给Michael的类增加了一个功能,可以从一个对象中移除所有的监听器,最后得到了这个:
class EventHook(object):
def __init__(self):
self.__handlers = []
def __iadd__(self, handler):
self.__handlers.append(handler)
return self
def __isub__(self, handler):
self.__handlers.remove(handler)
return self
def fire(self, *args, **keywargs):
for handler in self.__handlers:
handler(*args, **keywargs)
def clearObjectHandlers(self, inObject):
for theHandler in self.__handlers:
if theHandler.im_self == inObject:
self -= theHandler
我一直是这样做的:
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,也没有签名,这真让人失望。
PyPI 包
截至2022年10月,这里是PyPI上与事件相关的包,按最近的发布日期排序。
- PyDispatcher
2.0.6
: 2022年8月 - blinker
1.5
: 2022年6月 - pymitter
0.4.0
: 2022年6月 - python-dispatch
0.2.0
: 2022年4月 - pluggy
1.0.0
: 2021年8月 - Events
0.4
: 2020年10月 - zope.event
4.5.0
: 2020年9月 - RxPy3
1.0.1
: 2020年6月 - Louie
2.0
: 2019年9月 - PyPubSub
4.0.3
: 2019年1月 - pyeventdispatcher
0.2.3a0
: 2018年 - buslane
0.0.5
: 2018年 - PyPyDispatcher
2.1.2
: 2017年 - axel
0.0.7
: 2016年 - dispatcher
1.0
: 2012年 - py-notify
0.3.1
: 2008年
还有更多
有很多库可以选择,它们使用的术语各不相同(事件、信号、处理器、方法分发、钩子等)。
我在努力保持对上述包的概述,以及这里回答中提到的技术。
首先,来了解一些术语……
观察者模式
最基本的事件系统风格是“处理方法的集合”,这是对观察者模式的简单实现。
基本上,处理方法(可调用对象)被存储在一个数组中,当事件“触发”时,每个方法都会被调用。
发布-订阅
观察者事件系统的缺点是你只能在实际的事件对象(或处理器列表)上注册处理器。所以在注册时,事件必须已经存在。
这就是第二种事件系统风格存在的原因:发布-订阅模式。在这里,处理器不是在事件对象(或处理器列表)上注册,而是在一个中央调度器上。通知者只与调度器沟通。要监听什么,或者发布什么是由“信号”决定的,信号不过是一个名字(字符串)。
中介者模式
可能也会有兴趣的是:中介者模式。
钩子
钩子系统通常用于应用程序插件的上下文中。应用程序包含固定的集成点(钩子),每个插件可以连接到这个钩子并执行某些操作。
其他“事件”
注意:threading.Event并不是上述意义上的“事件系统”。它是一个线程同步系统,其中一个线程等待另一个线程“信号”事件对象。
网络消息库也常常使用“事件”这个术语;有时这些概念相似,有时则不然。它们当然可以跨越线程、进程和计算机的边界。比如pyzmq、pymq、Twisted、Tornado、gevent、eventlet。
弱引用
在Python中,持有对方法或对象的引用可以确保它不会被垃圾回收器删除。这可能是有利的,但也可能导致内存泄漏:链接的处理器永远不会被清理。
一些事件系统使用弱引用而不是常规引用来解决这个问题。
关于各种库的一些话
观察者风格的事件系统:
- zope.event展示了这个如何工作的基本框架(见Lennart的回答)。注意:这个例子甚至不支持处理器参数。
- LongPoke的“可调用列表”实现展示了如何通过子类化
list
来非常简约地实现这样的事件系统。 - Felk的变体EventHook也确保了被调用者和调用者的签名。
- spassig的EventHook(Michael Foord的事件模式)是一个简单明了的实现。
- Josip的Valued Lessons事件类基本上是相同的,但使用
set
而不是list
来存储集合,并实现了__call__
,这都是合理的补充。 - PyNotify在概念上类似,也提供了变量和条件的附加概念(“变量改变事件”)。主页不可用。
- axel基本上是一个处理器集合,具有更多与线程、错误处理等相关的功能。
- 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是一个非常简短的实现。
其他: