使用抽象类进行事件处理程序回调是惯用的Python吗?

2024-09-30 22:19:01 发布

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

我正在构建一个事件调度器框架,它将消息和调用解码回用户代码。我的C++背景表明我写的是:

class Handler:
    def onFoo(self):
        pass
    def onBar(self):
        pass

class Dispatcher:
    def __init__(self):
        self.handler = Handler()

    def run():
        while True:
            msg = decode_message() # magic
            if msg == 'foo':
                handler.onFoo()
            if msg == 'bar':
                handler.onBar()

然后,框架用户会写下如下内容:

^{pr2}$

但是我也可以想象将onFoo()和{}作为Dispatcher的方法,并让用户用其他方法替换它们。那么用户的代码将如下所示:

def onFoo():
    do_something()

dispatcher = Dispatcher()
dispatcher.onFoo = onFoo

我还可以使Dispatcher.onFoo成为一个可调用的列表,这样用户就可以像在C中那样附加多个处理程序。在

什么是最Python式的方法?在


Tags: 方法代码用户self框架ifdefmsg
1条回答
网友
1楼 · 发布于 2024-09-30 22:19:01

我不会说第一种方法有什么特别的错误,特别是如果你想让Dispatcher对象在运行时以有组织的方式进行定制(即通过向它们传递不同种类的Handler对象),如果你的Handler需要与它们交互并保持复杂的状态。在

但是这样定义基类Handler并不能真正获得任何好处;一个类仍然可以在不重写任何方法的情况下子类Handler,因为这不是一个抽象基类,它只是一个常规基类。因此,如果有一些合理的默认行为,我建议将它们构建到Handler。否则,您的用户根本不会从Handler中获得任何好处,他们不妨定义自己的Handler类。不过,如果您只想提供一个no-op占位符,那么这个设置就可以了。在

无论如何,我个人更喜欢第一种方法而不是您建议的第二种方法;我不确定哪一种方法更“pythonic”,但是第一种方法对我来说似乎是一种更干净的方法,因为它将Handler和{}逻辑分开。(它避免了您在threading.Thread中看到的那种情况,在这种情况下,您只能安全地重写一些我一直发现有点刺耳的方法。)

我觉得我应该指出,如果你真的想要一个真正的抽象基类,你应该写一个!从2.6开始,Python提供了对flexible abstract base classes的支持,并提供了许多不错的功能。例如,您可以使用abstractmethod修饰符定义一个抽象方法,这确保它必须被子类重写;但是您也可以定义不必重写的常规方法。如果您正在寻找一个python版本的c++习惯用法,这可能是最好的方法它当然不是同一回事,但它比您现在拥有的更接近。在

相关问题 更多 >