Python泛型列表过滤函数的类型收窄实现问题
解决方案
Python 3.11+(推荐)
利用Python 3.11引入的泛型方法语法,可以直接在方法上声明类型参数V并约束它为T的子类型,同时让类型检查器正确推断返回类型:
from typing import Generic, TypeVar, Type T = TypeVar('T') class BazList(Generic[T]): def __init__(self) -> None: self.data: list[T] = [] # 用[V: T]声明V是T的子类型 def filter[V: T](self, type__: Type[V]) -> list[V]: return [d for d in self.data if isinstance(d, type__)]
测试验证:
lst = BazList[int | str]() lst.filter(float) # 类型检查报错:float不是int | str的子类型,符合要求 filtered = lst.filter(int) # 类型推断为list[int],符合要求
Python 3.10及以下兼容方案
如果无法使用Python 3.11的泛型方法,可以结合TypeGuard和cast实现类型收窄,同时通过类型注释约束参数类型:
from typing import Generic, TypeVar, Type, TypeGuard, cast T = TypeVar('T') V = TypeVar('V', bound=T) class BazList(Generic[T]): def __init__(self) -> None: self.data: list[T] = [] def _is_target_type(self, item: T, type__: Type[V]) -> TypeGuard[V]: return isinstance(item, type__) def filter(self, type__: Type[V]) -> list[V]: result = [] for item in self.data: if self._is_target_type(item, type__): result.append(item) return cast(list[V], result)
这个方案中:
V绑定到T,确保传入的type__必须是T的子类型,类型检查器会拦截float这类不符合的参数;TypeGuard帮助类型检查器识别符合条件的元素,结合cast确保返回类型被正确收窄。
为什么之前的方案无法同时满足需求
FooList的filter参数用Type[T],虽然能拦截无关类型,但返回类型无法收窄——类型检查器无法推断isinstance过滤后的元素是T的子类型;BarList的filter用无约束的V,虽然能收窄返回类型,但无法限制传入的类型必须是T的子类型,导致可以传入float这类无效类型。
内容的提问来源于stack exchange,提问作者HairyNopper
相关产品推荐
相关产品推荐

