查看twisted.words.protocols.irc.IRCClient,在我看来似乎有一些奇怪的冗余方法。例如,有一个方法“privmsg”,但也有一个方法“irc_PRIVMSG”
作为另一个例子,考虑'join'和'irc_JOIN'
我想知道的是为什么会出现冗余,这只是众多例子中的两个。这两种不同的类型是否在不同的上下文中使用?我们应该使用一种类型而不是另一种吗?
对于在不同上下文中使用的两种不同类型的方法,您处于正确的轨道上。这实际上可以通过检查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
and之类的方法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_*
级别。将调用您的方法而不是定义 on 的方法IRCClient
,因此您可以以较低级别的格式处理数据,甚至不会调用较高级别的回调(除非您在覆盖该方法时还调用了基本实现)。
您还会发现有些 IRC 消息IRCClient
甚至没有定义irc_*
方法。正如我们在上面的handleCommand
方法中看到的,这些都进入了irc_unknown
回调。但是,如果您在子类irc_*
上定义了一个方法IRCClient
,那么handleCommand
将开始将数据传递给该方法。显然,在这些情况下,您唯一的选择是定义irc_*
方法,因为没有更高级别的回调(如privmsg
/irc_PRIVMSG
情况privmsg
下)。
irc_*
如果您愿意,您可以按照类似的方式构建方法的实现IRCClient
——我通常觉得这样做很有帮助,因为它使单元测试更容易,并使协议解析逻辑与应用程序逻辑分开——但这取决于你。