- 后端
- 即时通讯
【免费下载链接】nonebot2
跨平台 Python 异步聊天机器人框架 / Asynchronous multi-platform chatbot framework written in Python
nonebot.typing是 NoneBot2 框架中承载"共享类型"的公共模块,它集中定义了事件处理状态、各类钩子函数(Bot 连接、API 调用、事件预处理等)、规则/权限检查器、会话更新器以及依赖缓存的类型别名与底层类型工具函数。本文以 2.4.4 版本文档(typing.md)为主线,结合当前仓库源码(nonebot/typing.py)及其调用方实现,逐项讲解每个类型与函数的作用、签名、依赖参数与底层调用链,帮助你在编写插件、自定义钩子或适配器时正确使用这些类型。
模块定位:为框架各模块共享的类型"立规矩"
nonebot.typing模块的定位非常纯粹:定义 NoneBot 各模块之间共享的类型。它不包含业务逻辑,而是为整个框架提供统一的"类型词汇表",让事件响应器(Matcher)、规则(Rule)、权限(Permission)、钩子系统、依赖注入等模块在相互协作时有一致的类型契约。
从源码可见(nonebot/typing.py),该模块完全遵循 Python 官方类型标准:使用 PEP 484(类型注解)、PEP 526(变量注解)语法,并基于标准库typing构建。多数类型别名通过TypeAlias声明,并辅以丰富的 docstring 说明其允许的依赖参数。
模块内定义的实体大致可分为四类:
| 类别 | 成员 | 用途 |
|---|---|---|
| 底层类型工具函数 | overrides、type_has_args、origin_is_union、origin_is_literal、all_literal_values、origin_is_annotated、is_none_type、is_type_alias_type、evaluate_forwardref | 供框架内部解析类型注解 |
| 事件处理状态 | StateFlag、T_State | 会话/事件处理中的状态字典类型 |
| 钩子与处理器类型 | T_BotConnectionHook、T_BotDisconnectionHook、T_CallingAPIHook、T_CalledAPIHook、T_EventPreProcessor、T_EventPostProcessor、T_RunPreProcessor、T_RunPostProcessor、T_RuleChecker、T_PermissionChecker、T_Handler、T_TypeUpdater、T_PermissionUpdater | 各生命周期回调的签名契约 |
| 依赖缓存 | T_DependencyCache | 依赖注入结果缓存 |
底层类型工具函数:框架解析类型注解的"工具箱"
nonebot.typing提供的这一组纯函数,用于在运行时判断、解析各种 PEP 484/526 类型构造,它们是框架内部实现依赖注入、参数解析的基础设施,普通插件开发者一般不会直接调用,但理解它们有助于把握 NoneBot 的参数注入机制。
overrides(InterfaceClass)
- 说明:标记一个方法为父类 interface 的 implement。
- 参数:
InterfaceClass(object) - 返回:untyped
需要注意,当前源码中该函数已进入弃用流程:调用时会发出DeprecationWarning,提示改用@typing_extensions.override(对应 PEP 698),参见 nonebot/typing.py。在框架内部(如 nonebot/internal/params.py),各参数注入类重写_check_param时已直接使用typing_extensions.override。
type_has_args(type_)
- 参数:
type_(type[Any]) - 返回:bool
判断一个类型对象是否携带类型参数(即"泛型实例"),实现为检查isinstance(type_, (t._GenericAlias, types.GenericAlias, types.UnionType))(nonebot/typing.py)。例如list[int]、dict[str, Any]均携带参数,而裸的list不携带。
origin_is_union(origin)
- 参数:
origin(type[Any] | None) - 返回:bool
判断某个类型的 origin 是否为 Union 类型,同时兼容typing.Union与types.UnionType(即 Python 3.10+ 的X | Y语法)(nonebot/typing.py)。这保证了框架同时支持旧式Union[A, B]与新式A | B两种写法。
origin_is_literal(origin)与all_literal_values(type_)
- 说明:
origin_is_literal判断是否是Literal类型;all_literal_values获取Literal类型包含的所有值。 - 参数:
origin(type[Any] | None);type_(type[Any]) - 返回:bool;list[Any]
origin_is_literal同时兼容typing.Literal与typing_extensions.Literal(nonebot/typing.py)。all_literal_values则递归展开Literal的所有取值:如果类型不是Literal,直接返回[type_];否则对其每个类型参数递归收集(nonebot/typing.py),从而支持Literal[1, 2, Literal[3]]这类嵌套写法。
origin_is_annotated(origin)
- 说明:判断是否是
Annotated类型。 - 参数:
origin(type[Any] | None) - 返回:bool
实现对typing_extensions.Annotated的 origin 判断(nonebot/typing.py)。Annotated在 NoneBot 中有特殊用途:T_State正是借助Annotated携带一个标记对象,供参数注入识别(详见下文T_State一节)。
is_none_type(type_)
- 说明:判断是否是
None类型。 - 参数:
type_(type[Any]) - 返回:bool
实现为成员判断:type_ in NONE_TYPES,其中NONE_TYPES覆盖了None、type(None)、Literal[None](typing 与 typing_extensions 两个版本)以及types.NoneType(nonebot/typing.py),保证各写法下都能正确识别。
is_type_alias_type(type_)
- 参数:
type_(type[Any]) - 返回:bool
判断是否为TypeAliasType类型。实现针对 Python 版本做了分支:3.12 之前仅检查typing_extensions.TypeAliasType,3.12+ 同时检查标准库typing.TypeAliasType(nonebot/typing.py)。
evaluate_forwardref(ref, globalns, localns)
- 参数:
ref(ForwardRef);globalns(dict[str, Any]);localns(dict[str, Any]) - 返回:Any
求值一个前向引用(ForwardRef)。源码中特别说明:Python 3.13 / 3.12.4+ 将recursive_guard变为关键字参数,因此显式以recursive_guard=frozenset()命名调用ref._evaluate(globalns, localns, recursive_guard=frozenset()),以兼容不同 Python 版本(nonebot/typing.py)。
StateFlag与T_State:带"标记"的事件处理状态
StateFlag(class):一个无字段的标记类,其__repr__返回"StateFlag()"。它本身不承载数据,仅作为"哨兵"对象存在。T_State(var):类型为dict[Any, Any],说明为"事件处理状态 State 类型"。
源码实现为:
_STATE_FLAG = StateFlag() T_State: TypeAlias = t.Annotated[dict[t.Any, t.Any], _STATE_FLAG]这是Annotated在 NoneBot 中最典型的应用:T_State本质是dict[Any, Any],但通过Annotated附加了一个_STATE_FLAG标记。这样参数注入系统无需依赖字符串比较,即可精确识别"类型为T_State"的参数——在 nonebot/internal/params.py 中,StateParam._check_param正是通过origin_is_annotated(get_origin(param.annotation))且_STATE_FLAG in get_args(param.annotation)来判定注入的:
if origin_is_annotated(get_origin(param.annotation)) and _STATE_FLAG in get_args(param.annotation): return cls() # legacy: param is named "state" and has no type annotation elif param.annotation == param.empty and param.name == "state": return cls()这同时保证了向后兼容:即使不写类型注解,只要参数名为state也能注入。从源码注释看,使用Annotated标记还有一个目的:避免 Python 3.11+ 中ForwardRef重新创建泛型类型的问题(nonebot/typing.py)。
T_State贯穿整个事件处理链路:在 nonebot/message.py 中每个事件处理都会创建一个state: dict[Any, Any] = {};Matcher.run的_default_state也声明为ClassVar[T_State](nonebot/internal/matcher/matcher.py),事件响应器实例化时通过self._default_state.copy()初始化状态。
_DependentCallable:同步/异步双兼容的可调用类型
虽然_DependentCallable以下划线开头(私有类型,不在文档公开列表中),但它是理解整组类型别名的关键:
_DependentCallable: TypeAlias = t.Callable[..., T] | t.Callable[..., t.Awaitable[T]]它表示"一个返回T或Awaitable[T]的可调用对象"——即同时接受同步函数与异步函数。NoneBot 中所有处理器/钩子函数都既可以是普通def也可以是async def,框架在调用时会通过is_coroutine_callable判断并自动适配:同步函数经run_sync包装执行(nonebot/dependencies/init.py)。这正是T_RuleChecker、T_Handler等类型能以"同一签名兼容两种函数"为底层原因。
钩子类型族(一):Bot 生命周期与 API 调用钩子
T_BotConnectionHook与T_BotDisconnectionHook
- 类型:
_DependentCallable[Any] - 说明:Bot 连接建立/断开时执行的钩子函数。
两者允许的依赖参数完全相同:
DependParam:子依赖参数BotParam:Bot 对象DefaultParam:带有默认值的参数
对应的装饰器是Driver.on_bot_connect与Driver.on_bot_disconnect(nonebot/internal/driver/abstract.py),它们内部以BOT_HOOK_PARAMS = [DependParam, BotParam, DefaultParam](即文档列出的三种依赖参数)解析并存储钩子。实际触发链路为:_bot_connect/_bot_disconnect在连接建立/断开时被调用,钩子通过anyio任务组并发执行,并支持AsyncExitStack上下文与dependency_cache共享(nonebot/internal/driver/abstract.py)。因此钩子函数中可以声明bot: Bot参数直接拿到当前 Bot,也可以Depends()声明子依赖,还可以带默认值参数。
T_CallingAPIHook
- 类型:
(Bot, str, dict[str, Any]) -> Awaitable[Any] - 说明:
bot.call_api钩子函数,在真正调用 API 之前执行。
对应Bot.on_calling_api装饰器(nonebot/internal/adapter/bot.py),三个位置参数分别为 bot、API 名称(str)、API 参数字典(dict[str, Any])。在Bot.call_api的调用链中(nonebot/internal/adapter/bot.py),该钩子支持抛MockApiException来模拟 API 结果:一旦某个 hook 抛出该异常,框架会跳过真实 API 调用,直接返回异常中携带的 result——这是测试中 mock 机器人 API 的官方机制。
T_CalledAPIHook
- 类型:
(Bot, Exception | None, str, dict[str, Any], Any) -> Awaitable[Any] - 说明:
bot.call_api后执行的函数,参数分别为 bot、exception、api、data、result。
对应Bot.on_called_api(nonebot/internal/adapter/bot.py)。与 Calling 钩子不同,它多出exception(API 调用异常,可能为 None)与result(API 返回值)两个参数,且同样支持通过MockApiException改写返回值。典型用途包括:记录 API 调用结果、统一处理错误、在测试中拦截并替换返回数据。
钩子类型族(二):事件与响应器运行时的四类处理器
文档将事件处理流程中的钩子细分为四类,其依赖参数集合逐级递增,精确对应 nonebot/message.py 中定义的EVENT_PCS_PARAMS、RUN_PREPCS_PARAMS、RUN_POSTPCS_PARAMS三组允许参数。
T_EventPreProcessor/T_EventPostProcessor
- 类型:
_DependentCallable[Any] - 说明:事件预处理/后处理函数类型。
允许依赖参数:
DependParam:子依赖参数BotParam:Bot 对象EventParam:Event 对象StateParam:State 对象DefaultParam:带有默认值的参数
对应nonebot.message模块的event_preprocessor/event_postprocessor装饰器(nonebot/message.py)。事件预处理在事件分发到各响应器之前执行,若其中抛出IgnoredException,则该事件被忽略、不再分发(见_apply_event_preprocessors的实现,nonebot/message.py);事件后处理在分发完成后执行。
T_RunPreProcessor/T_RunPostProcessor
- 类型:
_DependentCallable[Any] - 说明:事件响应器运行前/后处理函数类型。
T_RunPreProcessor允许依赖参数:
DependParam、BotParam、EventParam、StateParam、MatcherParam(Matcher 对象)、DefaultParam
T_RunPostProcessor在T_RunPreProcessor基础上额外允许ExceptionParam(异常对象,可能为 None):
DependParam、BotParam、EventParam、StateParam、MatcherParam、ExceptionParam、DefaultParam
对应run_preprocessor/run_postprocessor装饰器(nonebot/message.py)。运行前处理在Matcher.run执行前触发,可抛出IgnoredException取消本次运行;运行后处理则接收响应器运行中捕获的异常(nonebot/message.py),因此后处理函数可以这样声明异常参数:
from nonebot import run_postprocessor @run_postprocessor async def log_exception( matcher: Matcher, exception: Exception | None, ): if exception: logger.error(f"Matcher {matcher} 运行失败: {exception!r}")ExceptionParam的实现见 nonebot/internal/params.py:它解析类型为Exception(或其子类)或None的参数,也兼容无注解但名为exception的参数。
规则与权限检查器:T_RuleChecker与T_PermissionChecker
T_RuleChecker
- 类型:
_DependentCallable[bool] - 说明:RuleChecker 即判断是否响应事件的处理函数。
允许依赖参数:
DependParam、BotParam、EventParam、StateParam、DefaultParam
它对应 nonebot/internal/rule.py 中Rule.HANDLER_PARAM_TYPES的[DependParam, BotParam, EventParam, StateParam, DefaultParam]。Rule在__init__中通过Dependent[bool].parse(call=checker, allow_types=self.HANDLER_PARAM_TYPES)解析每个检查器。规则语义为与(AND):所有检查器返回 True 才通过,且Rule之间只允许&合并(|会抛出RuntimeError)。
由于检查器可以Depends()子依赖、携带默认值参数,规则函数也能复用框架的依赖注入能力。
T_PermissionChecker
- 类型:
_DependentCallable[bool] - 说明:PermissionChecker 即判断事件是否满足权限的处理函数。
允许依赖参数:
DependParam、BotParam、EventParam、DefaultParam
注意与T_RuleChecker的差别:不包含StateParam——权限判断与事件状态无关。这与 nonebot/internal/permission.py 中Permission.HANDLER_PARAM_TYPES = [DependParam, BotParam, EventParam, DefaultParam]完全一致。权限语义为或(OR):任一检查器通过即满足权限(nonebot/internal/permission.py),且Permission之间用|合并,&不被允许。
典型的权限检查器写法(如只允许特定会话触发):
from nonebot.permission import Permission from nonebot.typing import T_PermissionChecker async def only_admin(bot: Bot, event: Event) -> bool: # 返回是否满足"管理员"条件 return ... matcher = on_command("admin", permission=Permission(only_admin))会话控制更新器:T_TypeUpdater与T_PermissionUpdater
T_TypeUpdater
- 类型:
_DependentCallable[str] - 说明:在
Matcher.pause、Matcher.reject时被运行,用于更新响应的事件类型,默认会更新为message。
允许依赖参数:DependParam、BotParam、EventParam、StateParam、MatcherParam、DefaultParam。
对应Matcher.type_updater类装饰器(nonebot/internal/matcher/matcher.py),它把函数解析为Dependent[str]存入_default_type_updater。在Matcher.update_type中(nonebot/internal/matcher/matcher.py),如果没有注册更新器,则直接返回字符串"message":
return ( await updater(bot=bot, event=event, state=self.state, matcher=self, ...) if updater else "message" )T_PermissionUpdater
- 类型:
_DependentCallable[Permission] - 说明:在
Matcher.pause、Matcher.reject时被运行,用于更新会话对象权限,默认会更新为当前事件的触发对象。
允许依赖参数:DependParam、BotParam、EventParam、StateParam、MatcherParam、DefaultParam。
对应Matcher.permission_updater(nonebot/internal/matcher/matcher.py)。默认实现update_permission在没有更新器时,返回Permission(User.from_event(event, perm=self.permission))(nonebot/internal/matcher/matcher.py)——即把会话权限收敛到"当前事件触发者本人"。
这两个更新器与pause/reject的配合发生在Matcher.run的异常分支:当捕获到RejectedException或PausedException时,框架会先update_type再update_permission,然后以priority=0、temp=True、block=True创建一个新的临时响应器接管后续会话(nonebot/internal/matcher/matcher.py),从而实现"暂停会话等用户下一条消息"的交互能力。这与文档中"默认会更新为message"、"默认会更新为当前事件的触发对象"的描述一一对应。
T_DependencyCache:依赖缓存类型
- 类型:
dict[_DependentCallable[Any], DependencyCache] - 说明:依赖缓存,用于存储依赖函数的返回值。
DependencyCache类定义于 nonebot/internal/params.py:包含PENDING/FINISHED两种状态,可保存结果或异常,并通过anyio.Event支持并发等待。T_DependencyCache是"以依赖函数为键、以缓存对象为值"的字典。
缓存的作用贯穿整个事件处理链路:
- 在
handle_event中,每个事件处理创建一个dependency_cache: T_DependencyCache = {}(nonebot/message.py),随stack一起传入各级检查器、处理器与钩子; - 在
DependParam._solve中(nonebot/internal/params.py),当use_cache=True且call in dependency_cache时,直接await dependency_cache[call].wait()复用结果,避免同一事件内重复计算子依赖。
因此,如果你在一个处理器里多次Depends同一个函数,默认情况下该函数只会执行一次,这正是Depends(use_cache=True)默认行为的底层实现。
综合示例:在一个插件中运用多个共享类型
将上述类型串联起来,一个典型的插件可以同时涉及状态、规则、处理器与钩子:
from typing import Any from nonebot import on_command, run_preprocessor, event_preprocessor from nonebot.matcher import Matcher from nonebot.adapters import Bot, Event from nonebot.typing import T_State # T_State 注入事件处理状态 @on_command("demo").handle() async def demo_handler(bot: Bot, event: Event, state: T_State): state["visited"] = True # 写入状态 await bot.send(event, "ok") # T_RunPreProcessor 风格的运行前钩子(MatcherParam 可注入) @run_preprocessor async def before_run(matcher: Matcher, bot: Bot, event: Event): ... # T_EventPreProcessor 风格的事件预处理(StateParam 可注入) @event_preprocessor async def before_event(bot: Bot, event: Event, state: T_State): ...小结
nonebot.typing是理解 NoneBot2 内部协作机制的一把钥匙:
- 底层工具函数负责在运行时解析
Union、Literal、Annotated、ForwardRef等类型构造,支撑依赖注入系统; T_State借助Annotated标记实现精确的状态参数注入;_DependentCallable让所有处理器/钩子统一支持同步与异步两种写法;- 十余个
T_*类型别名精确规定了每个生命周期钩子可注入的依赖参数集合,与 nonebot/internal/driver/abstract.py、nonebot/internal/adapter/bot.py、nonebot/message.py、nonebot/internal/rule.py、nonebot/internal/permission.py 等实现中的HANDLER_PARAM_TYPES/*_PARAMS常量一一对应。
编写插件时,按文档标注的依赖参数声明钩子与检查器即可获得完整的依赖注入能力;深入阅读 nonebot/typing.py 与上述调用方源码,则能进一步理解参数解析、缓存复用与会话暂停/拒绝等机制的底层原理。
- 后端
- 即时通讯
【免费下载链接】nonebot2
跨平台 Python 异步聊天机器人框架 / Asynchronous multi-platform chatbot framework written in Python
相关推荐
用 VoxCPM ZipEnhancer 给参考音频降噪的实操方法,3步让克隆更干净
用 VoxCPM ZipEnhancer 给参考音频降噪的实操方法,3步让克隆更干净 这篇 VoxCPM 实操只讲一件事:内置的音频增强器 ZipEnhance
后端即时通讯Roc 编译器类型依赖分析:Tag 构造器名称为何不计入类型别名依赖
Roc 编译器类型依赖分析:Tag 构造器名称为何不计入类型别名依赖 本篇文章基于 Roc 编译仓库(项目定位:A fast, friendly, functi
ReScript Compiler类型系统高级特性:泛型与模块签名
ReScript Compiler类型系统高级特性:泛型与模块签名 ReScript是一种强类型语言,它编译为高效且人类可读的JavaScript。其类型系统是
编译器编程语言开发工具
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考