Python PubSub 订阅多个主题

2 投票
3 回答
3024 浏览
提问于 2025-04-17 22:40

这听起来可能有点笼统,但其实问题很简单。就是想知道能不能用pubsub模块来订阅一部分主题。

让我简单说一下我想实现的目标。在一个wxpython项目中,我想根据不同的事件来改变状态栏的文本。所以我想要一个函数(一个监听器),它可以订阅一组主题。在这个监听器里,我会用if语句和几个elif语句来检查主题的名称。然后根据不同的主题,状态栏的文本就会相应地改变。

这样做可行吗?还是说一开始就不应该这么做?我该如何处理这种情况呢?谢谢!

3 个回答

0

另一种方法是多次调用 pub.subscribe,为同一个订阅者函数指定不同的子主题。比如说,你有一个电子邮件垃圾邮件过滤器,它把垃圾邮件分成20个不同的具体类别,这些类别可以分成五组。此时你只想处理这五组中的两个组。下面是一种实现方式:

def delete_spam_subscriber(header, message):
   delete_message(header, message)

def junkmail_subscriber(header, message):
   move_to_junk(header, message)

pub.subscribe(delete_spam_subscriber, 'root.spam.profanity')
pub.subscribe(delete_spam_subscriber, 'root.spam.spyware')
pub.subscribe(delete_spam_subscriber, 'root.spam.indirect')

pub.subscribe(junkmail_subscriber, 'root.spam.unknown_sender')
pub.subscribe(junkmail_subscriber, 'root.spam.forum_replys')
pub.subscribe(junkmail_subscriber, 'root.spam.receive_but_limit')

当然,这种方法适用于你不想通过分组主题来创建,比如 'root.spam.deletables' 和 'root.spam.to_junk_folder'。

1

首先,这样做其实并不好。你应该让发布-订阅(pubsub)来为你处理这些事情。每个主题只用一个监听器。这样做没有任何坏处,它可以把你的代码分开,让维护变得更简单,责任也更清晰。

不过,一个监听器可以监听基础主题:pub.subscribe('a.b', listener) 这样可以接收到主题 a.b、a.b.c、a.b.d、a.b.c.e 等等的消息。正如 pubsub 的文档所说,你可以通过使用一个默认值为 pub.AUTO_TOPIC 的关键字参数,让 pubsub 在消息中提供主题对象。但是如果你用这种方法,最后却写了一大堆 if/elif/else 的判断,那可能就不是最好的选择了。

也许如果你能提供更多关于你想要的主题层级和你心中想的 if/else 的细节,我可以给你更有用的建议。

0

有几种方法可以做到这一点。首先,可能最简单的方式是只用一个监听器。当你向这个监听器发送信息时,只需要传递不同的信息片段。例如,从A类你可以传一个字符串;从B类你可能传一个不同的字符串,但都是发给同一个监听器。然后在监听器里,你只需要检查是哪一个字符串,就可以了。

另一种方法是创建多个监听器,它们都绑定到同一个函数或方法上。这样你就可以向不同的监听器发送信息,它们都会调用同一个东西。

你应该选择你觉得最容易理解和调试的方法。

下面是一个例子:

import wx
from wx.lib.pubsub import pub 

########################################################################
class OtherFrame(wx.Frame):
    """"""

    #----------------------------------------------------------------------
    def __init__(self):
        """Constructor"""
        wx.Frame.__init__(self, None, wx.ID_ANY, "Secondary Frame")
        panel = wx.Panel(self)

        msg = "Enter a Message to send to the main frame"
        instructions = wx.StaticText(panel, label=msg)
        self.msgTxt = wx.TextCtrl(panel, value="")

        sendBtn = wx.Button(panel, label="Send Msg")
        sendBtn.Bind(wx.EVT_BUTTON, self.onSendMsg)

        closeBtn = wx.Button(panel, label="Send and Close")
        closeBtn.Bind(wx.EVT_BUTTON, self.onSendAndClose)

        sizer = wx.BoxSizer(wx.VERTICAL)
        flags = wx.ALL|wx.CENTER
        sizer.Add(instructions, 0, flags, 5)
        sizer.Add(self.msgTxt, 0, flags, 5)
        sizer.Add(sendBtn, 0, flags, 5)
        sizer.Add(closeBtn, 0, flags, 5)
        panel.SetSizer(sizer)

    #----------------------------------------------------------------------
    def onSendMsg(self, event):
        """"""
        msg = "Another message!"
        pub.sendMessage("anotherListener", 
                        message=msg,
                        listener="anotherListener")

    #----------------------------------------------------------------------
    def onSendAndClose(self, event):
        """
        Send a message and close frame
        """
        msg = self.msgTxt.GetValue()
        pub.sendMessage("panelListener", 
                        message=msg,
                        listener="panelListener")
        self.Close()

########################################################################
class MyPanel(wx.Panel):
    """"""

    #----------------------------------------------------------------------
    def __init__(self, parent):
        """Constructor"""
        wx.Panel.__init__(self, parent)
        pub.subscribe(self.myListener, "panelListener")
        pub.subscribe(self.myListener, "anotherListener")

        btn = wx.Button(self, label="Open Frame")
        btn.Bind(wx.EVT_BUTTON, self.onOpenFrame)

    #----------------------------------------------------------------------
    def myListener(self, message, listener=None):
        """
        Listener function
        """

        if listener == "panelListener":
            print "panel listener has sent the following: ",
            print message
        elif listener == "anotherListener":
            print "another listener sent the following: ", 
            print message

    #----------------------------------------------------------------------
    def onOpenFrame(self, event):
        """
        Opens secondary frame
        """
        frame = OtherFrame()
        frame.Show()

########################################################################
class MyFrame(wx.Frame):
    """"""

    #----------------------------------------------------------------------
    def __init__(self):
        """Constructor"""
        wx.Frame.__init__(self, None, title="New PubSub API Tutorial")
        panel = MyPanel(self)
        self.Show()

#----------------------------------------------------------------------
if __name__ == "__main__":
    app = wx.App(False)
    frame = MyFrame()
    app.MainLoop()

这是我教程中修改过的例子:http://www.blog.pythonlibrary.org/2013/09/05/wxpython-2-9-and-the-newer-pubsub-api-a-simple-tutorial/

撰写回答