关于在不同上下文中使用的两种不同类型的方法,您的思路是正确的。通过检查IRCClient 处理它接收到的数据的方式,实际上可以很容易地看出这一点。首先它将它们解析成行,然后将这些行拆分并传递给它自己的 handleCommand 方法:
def handleCommand(self, command, prefix, params):
"""Determine the function to call for the given command and call
it with the given arguments.
"""
method = getattr(self, "irc_%s" % command, None)
try:
if method is not None:
method(prefix, params)
else:
self.irc_unknown(prefix, command, params)
except:
log.deferr()
这是一个在 Twisted 协议实现中非常常见的模式示例,更普遍的是,在整个 Python 程序中。某些输入用于动态构造方法名称。然后getattr 用于查找该方法。如果找到,就调用它。
由于服务器正在发送诸如“PRIVMSG ...”和“JOIN ...”之类的客户端行,这导致IRCClient 查找诸如irc_PRIVMSG 和irc_JOIN 之类的方法。
这些irc_* 方法只是在行的拆分但未解析的其余部分被调用。这提供了消息附带的所有信息,但它并不总是最好的数据格式。例如,JOIN 消息包括包含主机掩码的用户名,但主机掩码通常无关紧要,只有昵称是需要的。所以JOIN 做了一些对于irc_* 方法来说相当典型的事情:它将粗略的数据转化为更易于使用的数据,并将结果传递给userJoined:
def irc_JOIN(self, prefix, params):
"""
Called when a user joins a channel.
"""
nick = string.split(prefix,'!')[0]
channel = params[-1]
if nick == self.nickname:
self.joined(channel)
else:
self.userJoined(nick, channel)
你可以看到这里还有一个条件,有时它调用joined而不是userJoined。这是从低级数据转换为应用程序开发人员应该更方便使用的数据的另一个示例。
这种分层应该可以帮助您决定在处理事件时要覆盖哪些方法。如果最高级别的回调,例如 userJoined、joined 或 privmsg 足以满足您的要求,那么您应该使用它们,因为它们会使您的任务变得最简单。另一方面,如果他们以不方便的格式呈现数据或以其他方式难以使用,您可以下拉到irc_* 级别。您的方法将被调用,而不是IRCClient 中定义的方法,因此您可以处理较低级别格式的数据,甚至不会调用较高级别的回调(除非您在覆盖方法)。
您还会发现IRCClient 甚至没有为其定义irc_* 方法的IRC 消息。正如我们在上面的handleCommand 方法中看到的,这些都转到irc_unknown 回调。但是,如果您在 IRCClient 子类上定义了 irc_* 方法,那么 handleCommand 将开始将数据传递给该方法。显然,在这些情况下,您唯一的选择是定义 irc_* 方法,因为没有更高级别的回调(如 irc_PRIVMSG/privmsg 案例中的 privmsg)。
如果你愿意,你可以像 IRCClient 那样构造你的 irc_* 方法的实现,我通常觉得这样做很有帮助,因为它使单元测试更容易,并使协议解析逻辑与应用程序逻辑 - 但这取决于您。