Python PubSub 订阅多个主题
这听起来可能有点笼统,但其实问题很简单。就是想知道能不能用pubsub模块来订阅一部分主题。
让我简单说一下我想实现的目标。在一个wxpython项目中,我想根据不同的事件来改变状态栏的文本。所以我想要一个函数(一个监听器),它可以订阅一组主题。在这个监听器里,我会用if语句和几个elif语句来检查主题的名称。然后根据不同的主题,状态栏的文本就会相应地改变。
这样做可行吗?还是说一开始就不应该这么做?我该如何处理这种情况呢?谢谢!
3 个回答
另一种方法是多次调用 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'。
首先,这样做其实并不好。你应该让发布-订阅(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 的细节,我可以给你更有用的建议。
有几种方法可以做到这一点。首先,可能最简单的方式是只用一个监听器。当你向这个监听器发送信息时,只需要传递不同的信息片段。例如,从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/