泛型类、类变量及staticmethod场景下的Mypy错误解决
解决Mypy泛型类型不兼容问题
问题复现代码
from typing import Generic, TypeVar, ClassVar, Type from abc import ABC, abstractmethod T = TypeVar("T") class Formatter(ABC, Generic[T]): @staticmethod @abstractmethod def format(x: T) -> T: ... class MyFormatter(Formatter[T]): @staticmethod def format(x: T) -> T: return x class FormattableClass(ABC, Generic[T]): formatter: ClassVar[Type[Formatter]] def __init__(self, x: T) -> None: self.x: T = x class SpecificFormattableClass(FormattableClass[T]): formatter = MyFormatter def __init__(self, x: T): self.x = self.formatter.format(x)
初始报错信息
Incompatible types in assignment (expression has type "T", variable has type "T")
错误根源是Mypy无法识别Formatter类的泛型T与FormattableClass的泛型T为同一类型变量——尽管名称相同,但二者作用域相互独立。
尝试的修改及新错误
尝试将FormattableClass中的formatter类型改为ClassVar[Type[Formatter[T]]]:
class FormattableClass(ABC, Generic[T]): - formatter: ClassVar[Type[Formatter]] + formatter: ClassVar[Type[Formatter[T]]] def __init__(self, x: T) -> None: self.x: T = x
但Mypy抛出新错误:
ClassVar cannot contain type variables
这是因为Mypy不允许类变量(ClassVar)包含泛型类型变量——类变量属于整个类,而泛型类型变量是每个子类/实例特有的属性。
解决方案
方案一:明确子类泛型参数
通过在子类中指定formatter的泛型参数,让Mypy正确关联类型:
from typing import Generic, TypeVar, ClassVar, Type from abc import ABC, abstractmethod T = TypeVar("T") class Formatter(ABC, Generic[T]): @staticmethod @abstractmethod def format(x: T) -> T: ... class MyFormatter(Formatter[T]): @staticmethod def format(x: T) -> T: return x class FormattableClass(ABC, Generic[T]): formatter: ClassVar[Type[Formatter]] def __init__(self, x: T) -> None: self.x: T = x class SpecificFormattableClass(FormattableClass[T]): # 明确指定MyFormatter的泛型参数为当前类的T formatter = MyFormatter[T] def __init__(self, x: T): self.x = self.formatter.format(x)
方案二:使用Protocol约束接口(更严谨)
通过定义Protocol来约束Formatter的接口,从根源避免泛型类型变量冲突:
from typing import Generic, TypeVar, ClassVar, Type, Protocol from abc import ABC, abstractmethod T = TypeVar("T") class FormatterProtocol(Protocol[T]): @staticmethod def format(x: T) -> T: ... class Formatter(ABC, Generic[T]): @staticmethod @abstractmethod def format(x: T) -> T: ... class MyFormatter(Formatter[T]): @staticmethod def format(x: T) -> T: return x class FormattableClass(ABC, Generic[T]): formatter: ClassVar[Type[FormatterProtocol[T]]] def __init__(self, x: T) -> None: self.x: T = x class SpecificFormattableClass(FormattableClass[T]): formatter = MyFormatter def __init__(self, x: T): self.x = self.formatter.format(x)
注意:该方案需要Mypy版本≥0.780以支持Protocol特性。
内容的提问来源于stack exchange,提问作者Marcos Bressan
相关产品推荐
相关产品推荐

