使用functools.singledispatch时遇AttributeError:'function'无'register'属性
问题解决方法
错误原因分析
AttributeError根源:注册实现时使用了和基础函数同名的my_func,直接覆盖了@singledispatch创建的调度对象(该对象带有register属性)。后续执行@my_func.register(list)时,my_func已经变成普通函数,自然没有register属性。- Typeguard警告根源:基础函数的参数未添加类型注解,导致typeguard无法执行类型检查,抛出警告。
修正后的代码
from functools import singledispatch from typeguard import typechecked from typing import Union, Any @singledispatch @typechecked def my_func(x: Any, y: Any) -> Union[int, str]: raise NotImplementedError(f'{type(x)} and/or {type(y)} are not supported.') @my_func.register(int) @typechecked def _my_func_int(x: int, y: int) -> Union[int, str]: try: return round(100 * x / (x + y)) except (ZeroDivisionError, TypeError, AssertionError) as e: return f'{e}' @my_func.register(list) @typechecked def _my_func_list(x: list, y: list) -> Union[int, str]: try: return round(100 * sum(x) / (sum(x) + sum(y))) except (ZeroDivisionError, TypeError, AssertionError) as e: return f'{e}' # 测试用例 a = my_func(1, 2) print(a) # 输出: 33 b = my_func([0, 1], [2, 3]) print(b) # 输出: 17 # 测试混合类型(触发基础函数逻辑) try: c = my_func(1, [2, 3]) print(c) except NotImplementedError as e: print(e) # 输出: <class 'int'> and/or <class 'list'> are not supported.
关键修复点
- 避免重名覆盖:给每个注册的实现函数使用独立名称(如
_my_func_int、_my_func_list),保留@singledispatch创建的调度对象。 - 添加类型注解:给基础函数参数添加
Any类型注解,消除typeguard的警告;注册函数的类型注解确保参数类型符合预期。 - 装饰器顺序:保持
@singledispatch为最外层装饰器,确保调度对象的register属性可用;每个实现函数也添加@typechecked,维持类型检查逻辑。 - 可选:多参数一致性检查:如果需要严格保证两个参数类型一致,可以在注册函数中添加额外检查,例如在
_my_func_int中判断isinstance(y, int),不符合则调用基础函数逻辑。
内容的提问来源于stack exchange,提问作者DanielBell99
相关产品推荐
相关产品推荐

