泛型继承中TypeVar绑定类触发mypy类型检查错误求助
解决mypy报错:
Incompatible return value type (got "Book", expected "BookParameter") 问题根源
在BookFinder的parse_parameters方法中,你直接返回Book(**parameters_dict),但BookParameter是绑定到Book的TypeVar——它代表任意Book子类或Book本身。当子类(比如LatinBookFinder)指定BookParameter为LatinBook时,返回父类Book的实例必然不符合子类类型要求,这就是mypy抛出类型不兼容错误的核心原因。
解决方案
以下是几种兼顾类型安全和抽象灵活性的修复方案:
方案1:通过抽象属性指定参数类
给BookFinder添加一个抽象属性,让子类明确声明自己要实例化的参数类型:
from dataclasses import dataclass from typing import Dict, TypeVar, Generic, Type, abc @dataclass class Model: var_1: str var_2: str class Book(Model): ... class Page(Model): ... PARAMETERS = TypeVar("PARAMETERS", bound=Model) RESULT = TypeVar("RESULT", bound=Model) class Finder(Generic[PARAMETERS, RESULT], metaclass=abc.ABCMeta): def run(self, parameters_dict: Dict[str, str]) -> RESULT: parameters = self.parse_parameters(parameters_dict) return self.do_stuff(parameters) @abc.abstractmethod def parse_parameters(self, parameters_dict: Dict[str, str]) -> PARAMETERS: ... @abc.abstractmethod def do_stuff(self, parameters: PARAMETERS) -> RESULT: ... BookParameter = TypeVar("BookParameter", bound=Book) BookResult = TypeVar("BookResult", bound=Page) class BookFinder(Generic[BookParameter, BookResult], Finder[BookParameter, BookResult], abc.ABC): @property @abc.abstractmethod def parameter_type(self) -> Type[BookParameter]: """返回当前Finder要实例化的参数类类型""" ... def parse_parameters(self, parameters_dict: Dict[str, str]) -> BookParameter: return self.parameter_type(**parameters_dict) @abc.abstractmethod def do_stuff(self, parameters: BookParameter) -> BookResult: ...
修改后的使用示例:
class ItalianBookFinder(BookFinder[Book, Page]): @property def parameter_type(self) -> Type[Book]: return Book def do_stuff(self, parameters: Book) -> Page: # 实现业务逻辑 ... class LatinBook(Book): var_3: str class LatinBookFinder(BookFinder[LatinBook, Page]): @property def parameter_type(self) -> Type[LatinBook]: return LatinBook def do_stuff(self, parameters: LatinBook) -> Page: # 实现业务逻辑 ...
方案2:用__init_subclass__简化子类声明
通过__init_subclass__让子类在定义时直接传入参数类型,避免重复编写属性:
# 基础Model、Finder定义同方案1,仅修改BookFinder class BookFinder(Generic[BookParameter, BookResult], Finder[BookParameter, BookResult], abc.ABC): parameter_type: Type[BookParameter] def __init_subclass__(cls, parameter_type: Type[BookParameter], **kwargs): super().__init_subclass__(**kwargs) cls.parameter_type = parameter_type def parse_parameters(self, parameters_dict: Dict[str, str]) -> BookParameter: return self.parameter_type(**parameters_dict) @abc.abstractmethod def do_stuff(self, parameters: BookParameter) -> BookResult: ...
使用示例:
class ItalianBookFinder(BookFinder[Book, Page], parameter_type=Book): def do_stuff(self, parameters: Book) -> Page: # 实现业务逻辑 ... class LatinBook(Book): var_3: str class LatinBookFinder(BookFinder[LatinBook, Page], parameter_type=LatinBook): def do_stuff(self, parameters: LatinBook) -> Page: # 实现业务逻辑 ...
方案3:简化抽象层级(仅当不需要扩展Book时使用)
如果你的业务场景中不需要Book的子类,可直接移除BookParameter TypeVar,用具体的Book类型替代:
class BookFinder(Finder[Book, BookResult], Generic[BookResult], abc.ABC): def parse_parameters(self, parameters_dict: Dict[str, str]) -> Book: return Book(**parameters_dict) @abc.abstractmethod def do_stuff(self, parameters: Book) -> BookResult: ...
内容的提问来源于stack exchange,提问作者jiripi
相关产品推荐
相关产品推荐

