
single_dispatch 要求第一个参数是类型判断依据
它只看被装饰函数的第一个参数的类型,然后匹配注册的实现。不是重载任意参数,也不是靠返回值或装饰器参数推断——就是死盯 obj 的实际类型(运行时 type(obj) 或其 MRO)。
常见错误现象:TypeError: singledispatch function must have at least one parameter,其实是你忘了给函数加参数,或者写了 @singledispatch 但函数签名是 def f():;另一个坑是传入 None,它没类型,会 fallback 到 object 实现,容易误以为“没匹配上”。
- 必须有一个且仅有一个位置参数作为分发目标(通常叫
obj或value) - 不能用关键字参数触发分发,
f(obj=42)依然看42的类型 - 如果想基于第二个参数分发,得手动包装一层,比如
f((a, b))再按元组元素类型 dispatch
register() 注册时别漏掉类型参数
@func.register 后面必须跟一个类型(如 str、int、Path),否则它注册的是 object,变成默认实现,所有未显式注册的类型都会走这里——这常导致你以为“注册了 str 却没生效”,其实是别的类型也进了这个分支。
使用场景:你想为内置类型和自定义类分别写逻辑,比如处理 str 做解析、bytes 做解码、Path 做文件读取。
立即学习“Python免费学习笔记(深入)”;
网趣网上购物系统支持PC电脑版+手机版+APP,数据一站式更新,支持微信支付与支付宝支付接口,是专业的网上商城系统,网趣商城系统支持淘宝数据包导入,实现与淘宝同步更新!支持上传图片水印设置、图片批量上传功能,同时支持订单二次编辑以及多级分类隐藏等实用功能,新版增加商品大图浏览与列表显示功能,使分类浏览更方便,支持最新的支付宝即时到帐接口。
-
@parse.register(str)→ 只对字符串生效 -
@parse.register()(无参数)→ 等价于@parse.register(object),是兜底行为 - 注册泛型类型(如
list)有效,但List[int]这种带参数的类型需 Python 3.9+ 且用typing.List不推荐,建议用list+ 运行时检查
继承关系下 dispatch 是按 MRO 查找的
它不是精确匹配,而是从 type(obj).__mro__ 从前到后找第一个注册过的类型。所以如果你注册了 Animal 和它的子类 Dog,传入 Dog() 会优先走 @f.register(Dog);但如果只注册了 Animal,Dog() 也会命中它。
性能影响很小,MRO 链一般很短;但兼容性要注意:如果你依赖某个父类注册的行为,又在子类里忘了注册,它就静默走父类逻辑,可能不符合预期。
- 子类实例不会自动触发父类注册函数,除非没为子类单独注册
- 用
issubclass(Dog, Animal)可验证是否真在 MRO 中 - 避免注册太宽泛的基类(如
object)在前,否则后面注册的具体类型可能永远不被执行
无法覆盖已注册类型,重复 register 会静默失败
同一个类型调用多次 @func.register(SomeType),只有第一次生效,后续的会被忽略,也不报错。调试时容易以为“我改了逻辑怎么没变”,其实是新注册没顶替旧的。
使用场景:开发中热重载或测试时反复 import 模块,可能导致同一类型被多次注册。
- 检查是否重复注册:打印
func.registry,它是个 dict,key 是类型,value 是函数 - 想强制更新?得清空 registry:
func.registry.clear(),再重新注册(仅限测试) - 正式代码里,注册逻辑应放在模块顶层,且只执行一次
from pathlib import Path 和 import pathlib 下的 pathlib.Path 在某些导入方式下可能被视为不同类型,dispatch 就断掉了。







