Python中的事件系统

2024-04-26 12:10:54 发布

您现在位置:Python中文网/ 问答频道 /正文

您使用什么Python事件系统?我已经知道pydispatcher,但我想知道还有什么可以找到,或者是常用的?

我对作为大型框架一部分的事件管理器不感兴趣,我宁愿使用一个简单的、易于扩展的解决方案。


Tags: 框架管理器系统事件解决方案pydispatcher
3条回答

我一直是这样做的:

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,也没有签名,这真的很糟糕。

我们使用Michael Foord在他的Event Pattern中建议的EventHook:

只需将EventHook添加到您的类中:

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()

我们将删除对象中所有侦听器的功能添加到Michaels类中,结果是:

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

总结以下答案中提到的各种事件系统:

事件系统最基本的样式是“处理程序方法包”,它是Observer pattern的简单实现。基本上,处理程序方法(callables)存储在一个数组中,并且在事件“激发”时分别被调用。

  • zope.event展示了这种方法的基本原理(请参见Lennart's answer)。注意:此示例甚至不支持处理程序参数。
  • LongPoke's 'callable list'实现表明,通过子类化list,这样的事件系统可以实现得非常少。
  • spassig's EventHook(Michael Foord的事件模式)是一个简单的实现。
  • Josip's Valued Lessons Event class基本上是相同的,但是使用set而不是list来存储包,并且实现了__call__,这两个都是合理的添加。
  • PyNotify在概念上类似,还提供了变量和条件(“变量更改事件”)的其他概念。
  • axel基本上是一个处理程序包,具有与线程、错误处理等相关的更多功能。。。

这些事件系统的缺点是只能在实际的事件对象(或处理程序列表)上注册处理程序。 因此在注册时,该事件已经需要存在。

这就是为什么存在第二种类型的事件系统:即publish-subscribe pattern。 在这里,处理程序不在事件对象(或处理程序列表)上注册,而是在中央调度程序上注册。同时,通知程序只与调度程序对话。监听什么或发布什么由“signal”决定,它只不过是一个名称(字符串)。

  • blinker具有自动断开和基于发送方的过滤等功能。
  • PyPubSub乍一看似乎很简单。
  • PyDispatcher似乎强调了多对多出版物等方面的灵活性
  • louie是一个重新设计的PyDispatcher,“提供插件基础设施,包括Twisted和PyQt特定的支持”。2016年1月之后,它似乎失去了保养。
  • django.dispatch是一个重写的PyDispatcher,“接口更有限,但性能更高”。
  • Qt的信号和插槽可以从PyQtPySide获得。它们在同一线程中使用时用作回调,或者在两个不同线程之间用作事件(使用事件循环)。信号和时隙有一个限制,即它们只能在派生自QObject的类的对象中工作。

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

注意:上面还没有包括pypydispatcherpython-dispatchpluggy的“钩子系统”可能也很有趣。

相关问题 更多 >