Python类型标注问题:实现含协议参数方法的协议具体类
解决Python协议与泛型类型不兼容的问题
问题根源在于函数参数的逆变特性和**list的不变性**:AnimalRepository的get方法要求接收list[Animal],但CatRepository的get只接受list[Cat]——根据里氏替换原则,子类方法的参数类型应是父类参数的超类型(逆变),而list[Cat]是list[Animal]的子类型,这直接导致了类型不兼容。
要在保持现有代码结构的前提下修复,需通过泛型协议关联动物类型与对应仓库类型,具体方案如下:
修正后的代码
from __future__ import annotations from dataclasses import dataclass from typing import TypeVar from typing_extensions import Protocol # 定义绑定到Animal协议的类型变量,限制只能是Animal的实现类 T = TypeVar('T', bound='Animal') @dataclass(frozen=True) class Animal(Protocol): age: int @dataclass(frozen=True) class Cat: age: int @dataclass(frozen=True) class Dog: age: int # 泛型协议,让仓库与特定动物类型绑定 class AnimalRepository(Protocol[T]): def get(self, animals: list[T]) -> None: ... class CatRepository: def get(self, animals: list[Cat]) -> None: pass class DogRepository: def get(self, animals: list[Dog]) -> None: pass # 泛型字典类型,确保键(动物类型)与值(对应仓库)的类型匹配 ANIMAL_TYPE_REPOSITORY_MAP: dict[type[T], AnimalRepository[T]] = { Cat: CatRepository(), Dog: DogRepository(), }
关键说明
- 泛型类型变量
T:通过bound='Animal'约束T只能是Animal协议的实现类(如Cat、Dog),保证类型安全。 - 泛型协议
AnimalRepository[T]:让每个仓库类对应特定的动物类型,get方法的参数也随之绑定到该类型的列表,解决了参数类型不匹配的核心问题。 - 泛型字典类型:
dict[type[T], AnimalRepository[T]]确保字典中每个动物类型(键)对应的仓库(值)恰好处理该类型的动物,完全符合类型系统的约束。
修改后,类型检查器会认可CatRepository和DogRepository是对应泛型AnimalRepository的合法实现,同时保留了原有的代码结构。
内容的提问来源于stack exchange,提问作者rokkuran
相关产品推荐
相关产品推荐

