为何错误MRO无法被mypy等静态类型检查器检测?
关于Python中Protocol、Generic继承顺序导致MRO错误及mypy检查通过的疑问
问题场景
以下代码在运行时会触发方法解析顺序(MRO)相关错误:
from dataclasses import dataclass from typing import Generic, Protocol, TypeVar T = TypeVar("T") class HasFoo(Protocol): foo: str class Mixin(HasFoo): foo = "test" @dataclass() class MyClass(Generic[T], Mixin): t: T
运行时错误信息
执行上述代码后,抛出如下错误:
Traceback (most recent call last): File "/home/veith/.config/JetBrains/PyCharm2022.2/scratches/scratch_4.py", line 16, in <module> class MyClass(Generic[T], FooMixin): File "/home/veith/.pyenv/versions/3.8.3/lib/python3.8/abc.py", line 85, in __new__ cls = super().__new__(mcls, name, bases, namespace, **kwargs) TypeError: Cannot create a consistent method resolution order (MRO) for bases Generic, Mixin
相关测试与猜测
我猜测该问题与Protocol接收泛型参数的机制有关,测试了几种泛型Protocol的写法:
# 标准泛型Protocol写法 class HasT(Protocol[T]): t: T # 等价的语法糖形式 class HasT(Protocol, Generic[T]): t: T # 颠倒Generic与Protocol顺序的写法,未触发错误 class HasT(Generic[T], Protocol): t: T
查阅PEP 544中关于泛型Protocol的章节,未找到相关说明。
解决方法
只需颠倒MyClass的继承顺序即可解决问题:
@dataclass() class MyClass(Mixin, Generic[T]): t: T
核心疑问
- 为何继承顺序会引发MRO不一致的错误?已知
Generic无父类,Protocol继承自Generic,理论上继承树存在循环依赖,但具体为何会导致MRO冲突? - 为何mypy 0.980能够通过对原错误代码的类型检查,未识别出该问题?
内容的提问来源于stack exchange,提问作者RunOrVeith
相关产品推荐
相关产品推荐

