看看twisted.words.protocols.irc.IRCClient,在我看来,有一些奇怪的冗余方法。例如,有一个方法'privmsg',但也有一个方法'irc_PRIVMSG'
另一个例子是'join'和'irc_JOIN'
我想知道的是为什么冗余,这只是众多的两个例子。这两种不同的类型是否在不同的环境中使用?我们应该使用一种类型而不是另一种吗?
答案 0 :(得分:4)
关于在不同环境中使用的两种不同类型的方法,您正走在正确的轨道上。通过检查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
回调。但是,如果在irc_*
子类上定义IRCClient
方法,则handleCommand
将开始将数据传递给该方法。显然,在这些情况下,您唯一的选择是定义irc_*
方法,因为没有更高级别的回调(例如privmsg
/ irc_PRIVMSG
案例中的privmsg
)。
您可以构建irc_*
方法的实现,类似于IRCClient
的方式,如果您愿意 - 我通常会发现这样做很有帮助,因为它使单元测试更容易并保持协议解析逻辑与应用程序逻辑分开 - 但这取决于你。