详解:从 RuleChecker 到内置规则的完整指南)
后端即时通讯【免费下载链接】nonebot2跨平台 Python 异步聊天机器人框架 / Asynchronous multi-platform chatbot framework written in Python项目地址https://gitcode.com/gh_mirrors/no/nonebot2点击查看免费下载本篇指南系统讲解 NoneBot 2 中的响应规则机制——从最小粒度的RuleChecker依赖函数到由多个检查器构成的Rule对象再到规则之间的合并、主动调用方式与全套内置规则。读完本文你将掌握如何为事件响应器编写自定义匹配条件、组合复用规则、判断事件是否满足条件并能直接使用startswith、command、regex、to_me等内置规则快速构建机器人行为。响应规则是 NoneBot 事件处理链路中的关键一环机器人会接收到多种多样的事件类型而 NoneBot 正是通过响应规则来决定哪些事件交由哪些事件响应器处理。在指南中我们为weather命令添加了ruleto_me()参数这个参数就是一个响应规则确保只有在私聊或者bot时才会响应。响应规则在事件处理流程中的位置在深入规则本身的 API 之前先理解它被调用的时机。NoneBot 的每个事件响应器Matcher都持有三个用于筛选事件的对象事件类型、事件触发权限与事件响应规则。从源码看事件响应器的check_rule方法会先校验事件类型再调用规则对象进行匹配nonebot/internal/matcher/matcher.pyclassmethod async def check_rule(cls, bot, event, state, stackNone, dependency_cacheNone) - bool: event_type event.get_type() return event_type (cls.type or event_type) and await cls.rule( bot, event, state, stack, dependency_cache )也就是说只有事件类型符合响应器声明、权限检查通过、且响应规则返回True时该响应器才会真正被触发。响应规则是整个筛选链条的最后一环也是开发者自由度最高的部分。RuleChecker最小的规则单元RuleChecker是一个返回值为bool类型的依赖函数即它支持 NoneBot 的依赖注入体系——函数参数中可以注入Bot、Event、State以及任意通过Depends声明的依赖。根据上一节中添加的配置项我们可以在weather插件目录中编写一个响应规则from nonebot import get_plugin_config from .config import Config plugin_config get_plugin_config(Config) async def is_enable() - bool: return plugin_config.weather_plugin_enabled weather on_command(天气, ruleis_enable)在上面的代码中我们定义了一个函数is_enable它会检查配置项weather_plugin_enabled是否为True。这个函数is_enable即为一个RuleChecker。注意这里的用法on_command(天气, ruleis_enable)直接传入了函数本身NoneBot 会自动将其包装为规则。is_enable不接收任何参数但这并不妨碍它成为合格的检查器——如果你需要访问事件数据只需在函数签名中声明event: Event参数NoneBot 的依赖注入便会自动传入当前事件。Rule多个检查器的集合Rule是若干个RuleChecker的集合它会并发调用每个RuleChecker只有当所有RuleChecker检查通过时匹配成功。例如我们可以组合两个RuleChecker一个用于检查插件是否启用一个用于检查用户是否在黑名单中from nonebot.rule import Rule from nonebot.adapters import Event async def is_enable() - bool: return plugin_config.weather_plugin_enabled async def is_blacklisted(event: Event) - bool: return event.get_user_id() not in BLACKLIST rule Rule(is_enable, is_blacklisted) weather on_command(天气, rulerule)这里的Rule(is_enable, is_blacklisted)会同时注册两个检查器插件未启用、或用户命中黑名单规则均不通过。并发执行与短路语义Rule内部将所有检查器封装为Dependent[bool]对象存入一个集合nonebot/internal/rule.py。调用时它会通过anyio.create_task_group()并发启动所有检查器并把每个检查器的结果做累加nonebot/internal/rule.pyasync def _run_checker(checker: Dependent[bool]) - None: nonlocal result # calculate the result first to avoid data racing is_passed await checker(...) result is_passed with catch({SkippedException: _handle_skipped_exception}): async with anyio.create_task_group() as tg: for checker in self.checkers: tg.start_soon(_run_checker, checker)源码揭示了两个重要细节并发执行所有检查器同时运行不会因前一个检查器失败而跳过后续检查器。因此检查器应当是纯判断性质的任务不应依赖前一个检查器先执行的顺序。SkippedException 语义若某个检查器抛出SkippedException该检查器视为跳过Rule将结果置为False即事件不会被响应。在测试用例中同样验证了这一行为Rule(skipped)返回False、Rule(truthy, skipped)返回Falsetests/test_rule.py。此外当Rule中没有任何检查器时调用会直接返回True空规则匹配一切事件。合并响应规则在定义响应规则时我们可以将规则进行细分来更好地复用规则。而在使用时我们需要合并多个规则。除了使用Rule对象来组合多个RuleChecker外我们还可以对Rule对象进行合并。在原weather插件中我们可以将ruleto_me()与ruleis_enable使用运算符合并from nonebot.rule import to_me from nonebot import get_plugin_config from .config import Config plugin_config get_plugin_config(Config) async def is_enable() - bool: return plugin_config.weather_plugin_enabled weather on_command( 天气, ruleto_me() is_enable, aliases{weather, 查天气}, priorityplugin_config.weather_command_priority, blockTrue, )这样weather命令就只会在插件启用且在私聊或者bot时才会响应。支持的合并形式合并响应规则可以有多种形式Rule对象与普通RuleChecker函数可以互相混合rule1 Rule(foo_checker) rule2 Rule(bar_checker) rule rule1 rule2 rule rule1 bar_checker rule foo_checker rule2从源码实现看Rule定义了__and__与__rand__两个运算符方法nonebot/internal/rule.py因此当rule在左侧时走__and__Rule(*self.checkers, *other.checkers)当rule在右侧如foo_checker rule2时走__rand__Rule(other, *self.checkers)合并的结果都是生成一个新的Rule包含两侧全部检查器原Rule对象不会被修改。与 None 合并同时我们也无需担心合并了一个None值Rule会忽略None值assert (rule None) is rule这个断言不仅成立而且语义相当明确与None合并时直接返回原Rule对象本身is判断通过这在需要条件性追加规则例如仅当开启某项功能时才加入某个检查器时非常实用。测试用例也覆盖了这一点tests/test_rule.py。关于|运算需要注意Rule不支持|运算——源码中__or__方法会直接抛出RuntimeError(Or operation between rules is not allowed.)nonebot/internal/rule.py。如果需要任一规则满足即可的逻辑请在单个RuleChecker函数内部自行实现或使用内置的keyword等多值规则。主动使用响应规则除了在事件响应器中使用响应规则外我们也可以主动使用响应规则来判断事件是否符合条件。例如rule Rule(some_checker) result: bool await rule(bot, event, state)我们只需要传入Bot对象、事件和会话状态Rule会并发调用所有RuleChecker进行检查并返回结果。Rule.__call__的完整签名还支持两个可选参数stack异步上下文栈与dependency_cache依赖缓存用于在更复杂的依赖注入场景下复用上下文nonebot/internal/rule.py。这一能力让规则不仅服务于事件响应器也可以作为独立的事件过滤器在业务逻辑中复用。内置响应规则NoneBot 内置了一些常用的响应规则可以直接通过事件响应器辅助函数如on_command、on_regex或者自行合并其他规则使用。这些规则均定义在 nonebot/rule.py 中完整列表及用法可以参考事件响应器进阶。下面结合源码逐一说明其匹配逻辑。startswith匹配消息开头匹配消息纯文本部分是否以指定字符串或一系列字符串开头支持ignorecase参数忽略大小写默认为False。实现上使用re.match锚定开头并把实际匹配到的前缀写入statenonebot/rule.pyfrom nonebot.rule import startswith # 匹配以 ! 或 / 开头的消息 rule startswith((!, /), ignorecaseFalse)endswith匹配消息结尾匹配消息纯文本部分是否以指定字符串结尾同样支持ignorecase实现使用re.search锚定结尾nonebot/rule.pyfrom nonebot.rule import endswith rule endswith((., 。), ignorecaseFalse)fullmatch完全匹配匹配消息纯文本是否与指定字符串完全相同支持ignorecase。与startswith/endswith不同它要求整条文本精确匹配而非包含关系nonebot/rule.pyfrom nonebot.rule import fullmatch rule fullmatch((ping, pong), ignorecaseFalse)keyword包含关键字匹配消息纯文本是否包含任一指定关键字并会把第一个命中的关键字写入statenonebot/rule.pyfrom nonebot.rule import keyword rule keyword(hello, hi)command命令匹配command是最常用的响应规则它根据配置中的command_start命令起始标记默认/与command_sep命令分隔标记默认.来判断消息是否为命令nonebot/config.pyfrom nonebot.rule import command # 匹配 /help 或者 /帮助 开头的消息 rule command(help, 帮助) # 匹配 /help.cmd 开头的消息 rule command((help, cmd))从源码结构看command规则的实现分为两层首先由TrieRule根据command_start/command_sep的笛卡尔积构建命令前缀字典树在消息到来时通过最长前缀匹配提取命令、空白符与参数nonebot/rule.py随后由CommandRule校验匹配到的命令是否在声明的命令列表中nonebot/rule.py。TrieRule.get_value也是测试用例重点覆盖的对象包括命令与参数之间的空白符、富文本消息段等边界情况tests/test_rule.py。另外command默认允许命令与参数之间不加空格如需严格约束可以使用force_whitespace参数它可以接收bool或具体字符串# 命令后必须有任意个数的空白符 rule command(help, force_whitespaceTrue) # 命令后必须恰好是一个空格 rule command(help, force_whitespace )shell_command类 shell 命令shell_command首先像command一样进行命令匹配匹配成功后对命令参数做进一步解析。参数解析基于标准库argparse并在此基础上支持 NoneBot 的富文本Message序列nonebot/rule.pyfrom nonebot.rule import shell_command, ArgumentParser parser ArgumentParser() parser.add_argument(-v, --verbose, actionstore_true) rule shell_command(cmd, parserparser)解析结果可以通过ShellCommandArgv解析前的参数列表与ShellCommandArgs解析后的参数字典依赖注入获取如果解析失败ShellCommandArgs注入的将是ParserExit异常对象。测试用例完整覆盖了词法错误、缺参、帮助输出、富文本参数等场景tests/test_rule.py。regex正则匹配匹配消息字符串是否与指定正则表达式匹配。需要注意两点匹配使用search而非match如需从头匹配请使用r^xxx匹配对象是EventMessage的str字符串而非纯文本nonebot/rule.pyfrom nonebot.rule import regex import re rule regex(r[a-z], flagsre.IGNORECASE)匹配结果可以通过RegexStr、RegexGroup、RegexDict依赖注入获取测试用例验证了命名分组(?Pkey...)的捕获行为tests/test_rule.py。to_me与机器人相关匹配事件是否与机器人有关即私聊或消息中bot。实现上通过依赖注入EventToMe读取适配器计算好的to_me标志nonebot/rule.pyfrom nonebot.rule import to_me rule to_me()is_type事件类型匹配匹配事件是否属于指定的一个或多个事件类型实现为isinstance(event, self.types)判断nonebot/rule.pyfrom nonebot.rule import is_type from nonebot.adapters.onebot.v11 import PrivateMessageEvent, GroupMessageEvent rule is_type(PrivateMessageEvent, GroupMessageEvent)小结响应规则是 NoneBot 事件分发机制中筛选事件的核心手段其设计可以归纳为三个层次RuleChecker返回bool的依赖函数是规则的最小单元天然支持依赖注入可直接传入辅助函数Rule检查器的集合并发执行所有检查器、全部通过才匹配成功并通过运算支持灵活合并与None合并返回原对象内置规则startswith、endswith、fullmatch、keyword、command、shell_command、regex、to_me、is_type覆盖了绝大多数常见匹配场景既可以单独使用也可以作为RuleChecker与其他自定义规则自由组合。无论是根据配置开关控制插件响应、按用户身份过滤事件还是解析富文本命令参数响应规则都提供了统一、可组合、可测试的解决方案。相关实现与测试分别位于 nonebot/internal/rule.py、nonebot/rule.py 与 tests/test_rule.py可作为深入阅读与二次开发的参考。赞分享后端即时通讯【免费下载链接】nonebot2跨平台 Python 异步聊天机器人框架 / Asynchronous multi-platform chatbot framework written in Python项目地址https://gitcode.com/gh_mirrors/no/nonebot2点击查看免费下载相关推荐NoneBot 响应规则Rule完全指南从 RuleChecker 组合到内置规则实战NoneBot 响应规则Rule完全指南从 RuleChecker 组合到内置规则实战 NoneBot 作为跨平台异步聊天机器人框架通过响应规则来决后端即时通讯NoneBot2 响应规则Rule深度指南从 RuleChecker 组合到内置规则实战NoneBot2 响应规则Rule深度指南从 RuleChecker 组合到内置规则实战 导读 在 NoneBot2 中机器人会接收到来自各种适配器Q后端即时通讯NoneBot2 响应规则Rule全解析从 RuleChecker 依赖注入到内置规则与主动调用NoneBot2 响应规则Rule全解析从 RuleChecker 依赖注入到内置规则与主动调用 事件响应器Matcher是 NoneBot2 处理消后端即时通讯上一篇ModEngine2内存扫描技术动态查找和修改游戏内存的完整教程下一篇Valdi 组件可视化预览完全指南从静态 API 分析到 valdi preview 实时渲染与截图创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考