“方法名称”作为客户端方法与 irc_'METHODNAME'扭曲中

发布于 2024-09-07 08:32:17 字数 213 浏览 5 评论 0原文

看看twisted.words.protocols.irc.IRCClient,在我看来,有一些奇怪的冗余方法。例如,有一个方法“privmsg”,但也有一个方法“irc_PRIVMSG”

作为另一个例子,考虑“join”和“irc_JOIN”

我想知道为什么会出现冗余,这些只是许多例子中的两个例子。这两种不同的类型是否在不同的上下文中使用?我们应该使用一种类型而不是另一种吗?

Looking at twisted.words.protocols.irc.IRCClient, it seems to me like there are some strangely redundant methods. For instance, there is a method 'privmsg' but also a method 'irc_PRIVMSG'

As another example consider 'join' and 'irc_JOIN'

What I want to know is why the redundancy, those are just two examples of many. Are the two different types used in different contexts? Are we supposed to use one type and not another?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

夏天碎花小短裙 2024-09-14 08:32:17

关于在不同上下文中使用的两种不同类型的方法,您的思路是正确的。实际上,通过检查 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。这是从低级数据转换为更方便应用程序开发人员使用的数据的另一个示例。

这种分层应该可以帮助您决定在处理事件时要重写哪些方法。如果最高级别的回调(例如 userJoinedjoinedprivmsg 足以满足您的要求,那么您应该使用它们,因为它们会让您的任务变得最简单。另一方面,如果它们以不方便的格式呈现数据或难以以其他方式使用,您可以下降到irc_*级别。您的方法将被调用,而不是在 IRCClient 上定义的方法,因此您可以以较低级别的格式处理数据,并且甚至不会调用较高级别的回调(除非您还调用了基类)当您重写该方法时的实现)。

您还会发现有些 IRC 消息 IRCClient 甚至没有为其定义 irc_* 方法。正如我们在上面的 handleCommand 方法中看到的,这些都进入了 irc_unknown 回调。但是,如果您在 IRCClient 子类上定义了 irc_* 方法,则 handleCommand 将开始将数据传递给该方法。显然,在这些情况下,您唯一的选择是定义 irc_* 方法,因为没有更高级别的回调(例如 irc_PRIVMSG 中的 privmsg >/privmsg 案例)。

如果您愿意,您可以像 IRCClient 那样构造您的 irc_* 方法的实现 - 我通常发现这样做很有帮助,因为它使单元测试变得更容易并且将协议解析逻辑与应用程序逻辑分开 - 但这取决于您。

You're on the right track about the two different types of methods being used in different contexts. This can actually be seen quite easily by examining the way IRCClient handles data it receives. First it parses them into lines, then it splits the lines up and passes the pieces to its own handleCommand method:

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()

This is an example of a pattern that's quite common in Twisted protocol implementations and, even more generally, in Python programs as a whole. Some piece of the input is used to construct a method name dynamically. Then getattr is used to look up that method. If it is found, it is called.

Since the server is sending the client lines like "PRIVMSG ..." and "JOIN ...", this results in IRCClient looking up methods like irc_PRIVMSG and irc_JOIN.

These irc_* methods are just called with the split up but otherwise unparsed remainder of the line. This provides all of the information that came with the message, but it's not always the nicest format for the data to be in. For example, JOIN messages include usernames that include a hostmask, but often the hostmask is irrelevant and only the nickname is desired. So JOIN does something that's fairly typical for irc_* methods: it turns the rough data into something more pleasant to work with and passes the result on to 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)

You can see that there's also a conditional here, sometimes it calls joined instead of userJoined. This is another example of a transformation from the low-level data into something which is supposed to be more convenient for the application developer to work with.

This layering should help you decide which methods to override when handling events. If the highest level callback, such as userJoined, joined, or privmsg is sufficient for your requirements, then you should use those because they'll make your task the easiest. On the other hand, if they present the data in an inconvenient format or are awkward to use in some other way, you can drop down to the irc_* level. Your method will be called instead of the one defined on IRCClient, so you can handle the data in the lower-level format and the higher level callback won't even be invoked (unless you also invoke the base implementation when you override the method).

You'll also find there are IRC messages which IRCClient doesn't even define an irc_* method for. As we saw above in the handleCommand method, these all go to the irc_unknown callback. But if you define an irc_* method on your IRCClient subclass, then handleCommand will start passing the data to that method. Clearly in these cases, your only choice is to define the irc_* method, since there is no higher-level callback (like privmsg in the irc_PRIVMSG/privmsg case).

You can structure your implementations of irc_* methods similarly to the way IRCClient does, if you like - I usually find it helpful to do so, since it makes unit testing easier and keeps the protocol parsing logic separate from the application logic - but it's up to you.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文