Functools -- singledispatch
Python 不支持函数重载(同名函数不同参数类型)。
但 functools.singledispatch 让你可以按照“参数类型”自动分发到不同函数。
- 类似 Java/C++ 的函数重载
- 但基于“参数类型”进行分发
- 扩展性非常强(特别适合插件系统)
用法:
from functools import singledispatch
from functools import singledispatch
@singledispatch
def process(value):
raise NotImplementedError(f"不支持类型: {type(value)}")
@process.register
def _(value: int):
return f"整数:{value}"
@process.register
def _(value: str):
return f"字符串:{value}"
print(process(10))
print(process("hello"))
输出:
整数:10
字符串:hello
👉 同一个函数名 process,根据第一个参数类型自动调用不同函数
- dict / list / str / int 需要不同解析方式
- JSON 转换
- 数据格式化
- 根据股票数据不同格式做不同处理
process(obj)
调用者无需关注 obj 的类型。
不同模块可以使用:
@process.register
来扩展功能,而不需要修改主函数。
@singledispatch
def serialize(obj):
raise TypeError(f"不能序列化类型:{type(obj)}")
@serialize.register
def _(obj: int):
return str(obj)
@serialize.register
def _(obj: str):
return obj
@serialize.register
def _(obj: list):
return "[" + ", ".join(serialize(i)) + "]"
@serialize.register
def _(obj: dict):
return "{" + ", ".join(f"{k}: {serialize(v)}" for k, v in obj.items()) + "}"
@process.register(int)
def _(value):
return f"int: {value}"
适合无法注解类型的场景。
@singledispatch
def handle(x):
print("默认处理: ", x)
如果没有匹配类型,会调用默认函数。
class Animal: ...
class Dog(Animal): ...
@handle.register(Animal)
def _(x):
print("动物")
print(handle(Dog()))
输出:
动物
👉 如果类型未注册,会向上查找父类类型。
singledispatch 只看第一个参数类型。
如果你想基于多个参数类型分发,需要:
- singledispatchmethod
- 或第三方库 multimethod / multipledispatch
用于类的方法:
from functools import singledispatchmethod
class Processor:
@singledispatchmethod
def process(self, value):
raise NotImplementedError()
@process.register
def _(self, value: int):
return f"int: {value}"
@process.register
def _(self, value: str):
return f"str: {value}"
p = Processor()
print(p.process(10))
print(p.process("abc"))
| 功能 | singledispatch | match-case |
|---|---|---|
| 基于类型分发 | ✅ | ✅ |
| 可扩展性强 | ✅ | ❌ |
| 插件式扩展 | ✅ | ❌ |
| 支持复杂逻辑 | ✅ | ✅ |
| 适合框架 | ✅ | ❌ |
singledispatch 更适合构建扩展性的系统。
第一次调用某类型会进行注册和缓存
后续调用是 O(1) 查找,非常快。
from functools import singledispatch
@singledispatch
def func(x): ...
@func.register
def _(x: int): ...
@func.register
def _(x: str): ...
func(10) # 调用 int 版
func("hello") # 调用 str 版
特点:
- 按类型自动分发
- 可扩展
- 插件式设计最佳
- 仅根据第一个参数决定
- 支持继承链查找
- 支持方法版:singledispatchmethod