ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

NoneBot2 事件类型与重载:按事件与平台类型精细化处理机器人逻辑

NoneBot2 事件类型与重载:按事件与平台类型精细化处理机器人逻辑 后端即时通讯【免费下载链接】nonebot2跨平台 Python 异步聊天机器人框架 / Asynchronous multi-platform chatbot framework written in Python项目地址https://gitcode.com/gh_mirrors/no/nonebot2点击查看免费下载在 NoneBot2 中来自不同平台、不同场景的事件信息远比一条消息丰富得多例如消息发送时间、发送者身份、会话类型等而调用平台接口时也必须保证接口与平台类型严格匹配。本文围绕 NoneBot2 的事件类型体系与重载overload机制展开结合框架源码说明如何通过参数类型注解获取更多事件信息、如何让同一个事件响应器针对私聊/群聊或不同平台执行不同逻辑帮助你在编写跨平台、多场景插件时写出既精确又通用的代码。事件类型从基类抽象到协议适配器子类Event基类跨平台通用信息的抽象层在 NoneBot2 中所有平台上报的事件都是 Event 基类 的子类型。该基类继承自pydantic.BaseModel采用abc.ABC抽象基类设计对任何平台事件都具备的必要信息做了抽象而具体实现则交由各协议适配器完成。从 Event 基类源码 可以看到基类声明了以下抽象方法它们构成了跨平台通用能力的骨架抽象方法用途说明get_type()获取事件类型通常为 NoneBot 内置的四种类型之一如message、notice、request、meta_eventget_event_name()获取事件名称如私聊消息、群聊消息、入群通知等get_event_description()获取事件描述通常为事件具体内容get_user_id()获取事件主体 ID通常是用户 IDget_session_id()获取会话 ID用于判断事件属于哪个会话通常是用户 ID 与群组 ID 的组合get_message()获取事件消息内容get_plaintext()获取消息纯文本默认基于get_message().extract_plain_text()实现is_tome()判断事件是否与机器人有关此外基类还提供了__str__与get_log_string()用于日志输出。正如自定义权限一节中的示例所展示的Event的抽象方法如get_user_id由协议适配器实现返回机器人用户对应的平台 ID因此基于基类编写的逻辑天然具备跨平台能力。更完整的基类抽象方法清单可参阅使用适配器获取事件通用信息。子类型平台特有的扩展信息由于事件是基类的子类型实际运行时你能获得的信息通常远多于基类抽象方法所提供的部分。不同协议适配器会基于Event派生出自己的事件子类型并为这些子类型挂载平台特有的字段例如消息发送时间、消息发送者的昵称头像、消息 ID、群成员权限等。因此当你不满足于基类提供的信息时只需要把事件处理函数的事件参数类型注解缩小为对应的适配器子类型就能通过该子类型直接访问平台扩展属性。类型注解决定你能看到什么这是理解后续重载机制的关键前提。通过子类型注解获取更多事件信息我们以Console协议适配器为例。下面这段代码把事件参数注解为Console适配器的MessageEvent从而获取了基类中并不存在的发送时间time属性from nonebot.adapters.console import MessageEvent weather.got(location, prompt请输入地名) async def got_location(event: MessageEvent, location: str ArgPlainText()): await weather.finish(f{event.time.strftime(%Y-%m-%d)} {location} 的天气是...)这里event.time即为Console适配器消息事件提供的发送时间datetime对象通过strftime(%Y-%m-%d)可格式化为日期字符串。注意ArgPlainText()依赖来自 nonebot.internal.params 模块用于直接取出got收集到的纯文本参数与事件类型注解无关二者可以自由组合。通用性权衡能不改就别改:::warning[注意] 如果基类就能满足你的需求那么就不要修改事件参数类型注解这样可以使你的代码更加通用可以在更多平台上运行。如何根据不同平台事件类型进行不同的处理我们将在下一节重载中介绍。 :::把事件注解成具体适配器子类型意味着该处理函数只会绑定在该平台上运行——这是用跨平台通用性换取更丰富信息的取舍。正确做法是通用逻辑保持基类注解平台特有逻辑通过重载拆分。重载Overload按类型注解分发处理逻辑什么是重载编写机器人时经常遇到两个典型问题如何对私聊消息和群聊消息进行不同的处理如何对不同平台的事件进行不同的处理NoneBot2 为此提供了重载机制。简单来说依赖函数会根据其参数的类型注解来决定是否执行忽略不符合其参数类型注解的情况。一个事件响应器Matcher可以注册多个同名处理函数每个函数声明不同的参数类型注解事件到达后NoneBot 会依次尝试运行这些处理函数只有当参数类型注解与实际传入对象匹配时该函数才会真正执行不匹配的函数会被静默跳过。这样我们就可以通过修改事件参数类型注解实现对不同事件如私聊/群聊的分流处理通过修改Bot参数类型注解实现在不同平台上调用各自特有的接口。按事件类型分发私聊与群聊分别处理以OneBot协议适配器为例在同一个事件响应器上注册两个handle()处理函数分别注解为PrivateMessageEvent和GroupMessageEventfrom nonebot.adapters.onebot.v11 import PrivateMessageEvent, GroupMessageEvent matcher.handle() async def handle_private(event: PrivateMessageEvent): await matcher.finish(私聊消息) matcher.handle() async def handle_group(event: GroupMessageEvent): await matcher.finish(群聊消息)当事件实际为私聊消息时handle_private的类型注解匹配并执行返回私聊消息为群聊消息时handle_group匹配并执行返回群聊消息。机器人用户就会在私聊和群聊中分别收到不同的回复。按Bot类型分发不同平台调用不同接口同样的思路适用于Bot参数。不同适配器的Bot子类提供各自的平台接口例如Console适配器有bell()响铃OneBotv11 适配器有send_group_message()。通过注解不同的Bot子类型可以在同一个响应器中安全地调用平台特有接口from nonebot.adapters.console import Bot as ConsoleBot from nonebot.adapters.onebot.v11 import Bot as OneBot matcher.handle() async def handle_console(bot: ConsoleBot): await bot.bell() matcher.handle() async def handle_onebot(bot: OneBot): await bot.send_group_message(group_id123123, messageOneBot)当运行的平台是 Console 时handle_console被调用并触发bell()当平台是 OneBot v11 时handle_onebot被调用并调用send_group_message向指定群发送消息。平台接口与平台类型的一致性由重载机制自动保证你不再需要手写if isinstance(bot, ...)之类的判断。重载机制的源码级原理处理函数被解析为Dependent依赖容器在 Matcher 源码 中事件响应器定义了HANDLER_PARAM_TYPES即处理函数允许使用的参数注入类型HANDLER_PARAM_TYPES: ClassVar[tuple[Type[Param], ...]] ( DependParam, BotParam, EventParam, StateParam, ArgParam, MatcherParam, DefaultParam, )每个通过matcher.handle()注册的处理函数都会被 Dependent.parse 解析为Dependent容器。解析过程parse_params逐一检查函数签名的每个参数依次尝试allow_types中各类Param的_check_param方法为参数分配合适的注入器。EventParam与BotParam类型匹配检查的核心重载的关键在于参数类型匹配检查。以 EventParam 为例若参数注解是Event基类则不设置类型检查器任何事件都可注入若参数注解是某个子类型如PrivateMessageEvent则构造一个checkerModelField并在_check阶段调用check_field_type(self.checker, event)校验实际事件是否是该子类型为兼容旧代码还保留了参数名为event且无类型注解的兜底解析。BotParam 与 MatcherParam 的实现方式完全对称分别针对Bot与Matcher的类型注解做同样的检查。也就是说参数注解写成什么类型注入器就会以什么类型为标准去校验实际对象。类型不匹配时静默跳过类型检查失败时会发生什么看 check_field_type 实现校验失败会抛出TypeMisMatch异常。而 TypeMisMatch 继承自SkippedException——这是一个专门用于跳过当前处理函数的异常。在 Dependent.call中SkippedException会被catch捕获并记录为跳过整个处理函数不会执行事件流继续向下一个处理函数推进。这正是重载得以实现的底层链路类型注解 → 注入器生成 checker → 运行时校验实际对象 → 不匹配抛TypeMisMatch继承SkippedException→ 当前函数被跳过 → 尝试下一个处理函数在 Matcher.simple_run 中处理函数按注册顺序依次从remain_handlers弹出执行跳过异常被捕获后继续运行剩余处理函数最终总有一个类型注解匹配的处理函数成功执行。测试用例 tests/test_param.py 也验证了这一行为构造类型不匹配的依赖时pytest断言会捕获TypeMisMatch或包含该异常的BaseExceptionGroup确认类型检查失败会以跳过的形式结束本次处理。优先级规则Bot、Event、Matcher 先行:::warning[注意] 重载机制对所有的参数类型注解都有效因此依赖注入也可以使用这个特性来对不同的返回值进行处理。但Bot、Event 和 Matcher 三者的参数类型注解具有最高检查优先级如果三者任一类型注解不匹配那么其他依赖注入将不会执行如Depends。 :::这一点从HANDLER_PARAM_TYPES的排列顺序可以印证DependParam、BotParam、EventParam排在StateParam、ArgParam、MatcherParam之前。DependParam子依赖会先于其他参数解析而BotParam/EventParam的类型检查通过_check预处理阶段执行先于_solve参数求解阶段。因此若Bot、Event、Matcher中任一注解与实际对象不匹配整个处理函数会在预处理阶段被跳过后续的Depends子依赖自然不会执行。基于同样的机制你也可以让依赖注入如自定义Depends子依赖通过不同的返回值类型注解实现按返回类型分发重载并不局限于事件与 Bot 参数。实战建议与延伸阅读使用建议优先使用基类能用Event/Bot基类完成的需求就不要细化注解保持代码的跨平台通用性重载拆分平台逻辑平台特有逻辑如bell()、send_group_message通过注解具体子类型单独注册处理函数让重载机制替你完成类型分流注意处理顺序同一响应器内多个处理函数按注册顺序尝试匹配把更具体的类型放在前面、更通用的类型放在后面通常更符合直觉。延伸阅读如何获取事件的通用信息与更多基类抽象方法使用适配器获取事件通用信息事件信息与平台接口的基础用法事件数据、平台接口调用基于事件类型做权限控制权限控制如何更好地编写跨平台插件多平台适配最佳实践。# 回顾重载的三种典型用法一览 # 1. 用子类型获取更多事件信息 async def handler(event: MessageEvent): # Console 适配器 await matcher.finish(event.time.strftime(%Y-%m-%d)) # 2. 按事件类型分发私聊 / 群聊 matcher.handle() async def handle_private(event: PrivateMessageEvent): ... matcher.handle() async def handle_group(event: GroupMessageEvent): ... # 3. 按 Bot 类型调用不同平台接口 matcher.handle() async def handle_console(bot: ConsoleBot): ... matcher.handle() async def handle_onebot(bot: OneBot): ...赞分享后端即时通讯【免费下载链接】nonebot2跨平台 Python 异步聊天机器人框架 / Asynchronous multi-platform chatbot framework written in Python项目地址https://gitcode.com/gh_mirrors/no/nonebot2点击查看免费下载相关推荐如何把 Google Drive 设为 Cap 新上传录制的存储位置如何把 Google Drive 设为 Cap 新上传录制的存储位置 如果你的 Cap 团队希望把新录制的存储位置换成自己的 Google Drive——而不后端即时通讯NoneBot2 事件类型与重载用类型注解实现跨平台、分场景的事件处理NoneBot2 事件类型与重载用类型注解实现跨平台、分场景的事件处理 导读 在 NoneBot2 中事件Event与机器人Bot对象都拥有严格的类后端即时通讯深入理解ecs-refarch-cloudformation网络架构VPC设计与子网规划最佳实践深入理解ecs refarch cloudformation网络架构VPC设计与子网规划最佳实践 ecs refarch cloudformation是一个用上一篇三步搞定国家中小学智慧教育平台电子课本批量下载攻略下一篇Zotero Style插件科研文献管理的智能升级方案创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表