重写Literal类型参数方法时overrides触发RecursionError
问题描述
当重写带有Literal类型标注参数的方法时,第三方overrides模块会抛出RecursionError,栈追踪信息见下文。目前既不清楚该错误的触发原因,也不确定带Literal标注的方法是否支持正常重写。
补充说明:此处提到的
overrides为第三方模块,项目仓库地址为github.com/mkorpela/overrides
可复现该错误的最小示例代码如下:
from typing import Literal from overrides import overrides class Base: def foo(self, mode: Literal["train"]) -> None: raise NotImplementedError() class Child(Base): @overrides def foo(self, mode: Literal["train"]) -> None: pass
移除@overrides装饰器是可行的临时规避方案,不会改变代码实际运行行为,但优先希望保留该装饰器。原本计划将该参数类型替换为Enum,这也是设计层面更优的实现方案,但仍希望明确@overrides与Literal组合使用无法正常工作的根本原因。
错误栈追踪
Traceback (most recent call last): File "model-autotraining/temp.py", line 12, in <module> class ChildModel(BaseClass): File "model-autotraining/temp.py", line 14, in ChildModel def foo(self, mode: Literal["train"]) -> None: File "/opt/homebrew/Caskroom/miniforge/base/envs/worker/lib/python3.8/site-packages/overrides/overrides.py", line 88, in overrides return _overrides(method, check_signature, check_at_runtime) File "/opt/homebrew/Caskroom/miniforge/base/envs/worker/lib/python3.8/site-packages/overrides/overrides.py", line 114, in _overrides _validate_method(method, super_class, check_signature) File "/opt/homebrew/Caskroom/miniforge/base/envs/worker/lib/python3.8/site-packages/overrides/overrides.py", line 135, in _validate_method ensure_signature_is_compatible(super_method, method, is_static) File "/opt/homebrew/Caskroom/miniforge/base/envs/worker/lib/python3.8/site-packages/overrides/signature.py", line 94, in ensure_signature_is_compatible ensure_all_kwargs_defined_in_sub( File "/opt/homebrew/Caskroom/miniforge/base/envs/worker/lib/python3.8/site-packages/overrides/signature.py", line 153, in ensure_all_kwargs_defined_in_sub and not _issubtype(super_type_hints[name], sub_type_hints[name]) File "/opt/homebrew/Caskroom/miniforge/base/envs/worker/lib/python3.8/site-packages/overrides/signature.py", line 42, in _issubtype return issubtype(left, right) File "/opt/homebrew/Caskroom/miniforge/base/envs/worker/lib/python3.8/site-packages/typing_utils/__init__.py", line 428, in issubtype return _is_normal_subtype(normalize(left), normalize(right), forward_refs) File "/opt/homebrew/Caskroom/miniforge/base/envs/worker/lib/python3.8/site-packages/typing_utils/__init__.py", line 251, in normalize args = _normalize_args(args) File "/opt/homebrew/Caskroom/miniforge/base/envs/worker/lib/python3.8/site-packages/typing_utils/__init__.py", line 232, in _normalize_args return tuple(_normalize_args(type_) for type_ in tps) File "/opt/homebrew/Caskroom/miniforge/base/envs/worker/lib/python3.8/site-packages/typing_utils/__init__.py", line 232, in <genexpr> return tuple(_normalize_args(type_) for type_ in tps) File "/opt/homebrew/Caskroom/miniforge/base/envs/worker/lib/python3.8/site-packages/typing_utils/__init__.py", line 232, in _normalize_args return tuple(_normalize_args(type_) for type_ in tps) File "/opt/homebrew/Caskroom/miniforge/base/envs/worker/lib/python3.8/site-packages/typing_utils/__init__.py", line 232, in <genexpr> ... repeated many times ... File "/opt/homebrew/Caskroom/miniforge/base/envs/worker/lib/python3.8/site-packages/typing_utils/__init__.py", line 232, in _normalize_args return tuple(_normalize_args(type_) for type_ in tps) File "/opt/homebrew/Caskroom/miniforge/base/envs/worker/lib/python3.8/site-packages/typing_utils/__init__.py", line 232, in <genexpr> return tuple(_normalize_args(type_) for type_ in tps) File "/opt/homebrew/Caskroom/miniforge/base/envs/worker/lib/python3.8/site-packages/typing_utils/__init__.py", line 231, in _normalize_args if isinstance(tps, collections.abc.Sequence): File "/opt/homebrew/Caskroom/miniforge/base/envs/worker/lib/python3.8/abc.py", line 98, in __instancecheck__ return _abc_instancecheck(cls, instance) File "/opt/homebrew/Caskroom/miniforge/base/envs/worker/lib/python3.8/abc.py", line 102, in __subclasscheck__ return _abc_subclasscheck(cls, subclass) RecursionError: maximum recursion depth exceeded in comparison
问题根因
该错误是overrides依赖的typing_utils库在Python 3.8及以下版本中的类型解析bug导致的:
- Python 3.8版本的
typing.Literal实现未被旧版typing_utils的类型归一化逻辑正确识别,递归解析类型参数时,会将Literal包裹的字符串字面量(如示例中的"train")误判为可迭代的类型序列,无限递归调用_normalize_args方法,最终超出Python最大递归深度触发报错。 - 该bug仅存在于Python < 3.9 + 旧版本
overrides/typing_utils的组合环境中,新版依赖已经修复了该类型解析逻辑。
可行解决方案
- 升级依赖版本:将
overrides升级至6.1.0及以上版本,同步升级配套的typing_utils至0.1.0及以上版本,新版本已修复Literal类型的递归解析问题,可直接正常使用。 - 临时关闭签名检查:如果暂时无法升级依赖,可使用
@overrides(check_signature=False)写法,既保留装饰器的重写标记作用,也不会触发类型校验逻辑的bug。 - 替换类型实现:按照原计划将
Literal类型替换为Enum实现,该方案在类型设计上更严谨,也可完全规避该解析bug。
内容的提问来源于stack exchange,提问作者jkelle
相关产品推荐
相关产品推荐

