如何为泛型Number类的__add__方法编写灵活的Python类型提示?
解决泛型Number类跨类型加法的类型提示问题
要让泛型Number类支持跨数值类型(如int+float、Decimal+int等)的加法,同时让类型提示系统正确识别可接受的参数类型和返回结果类型,可以采用以下几种方案:
方案1:使用@overload明确声明跨类型场景
通过@overload装饰器为不同的参数类型组合定义精确的类型提示,适合需要严格类型校验的场景:
from typing import TypeVar, Generic, overload from decimal import Decimal from fractions import Fraction # 限定T为支持的数值类型 T = TypeVar('T', int, float, Decimal, Fraction) class Number(Generic[T]): value: T # 同类型相加 @overload def __add__(self, other: T) -> Number[T]: ... @overload def __add__(self, other: "Number[T]") -> Number[T]: ... # int与float跨类型相加 @overload def __add__(self, other: float) -> Number[float]: ... @overload def __add__(self, other: "Number[float]") -> Number[float]: ... @overload def __add__(self, other: int) -> Number[float]: ... @overload def __add__(self, other: "Number[int]") -> Number[float]: ... # Decimal与其他数值类型相加(结果为Decimal) @overload def __add__(self, other: int) -> Number[Decimal]: ... @overload def __add__(self, other: float) -> Number[Decimal]: ... @overload def __add__(self, other: Fraction) -> Number[Decimal]: ... @overload def __add__(self, other: "Number[int] | Number[float] | Number[Fraction]") -> Number[Decimal]: ... # 实际实现逻辑 def __add__(self, other): other_val = other.value if isinstance(other, Number) else other result_val = self.value + other_val return Number(value=result_val)
这种方式能让类型检查器(如mypy、pyright)精确推断每个加法场景的返回类型,但需要手动覆盖所有需要支持的跨类型组合。
方案2:结合Protocol与关联泛型类型变量
定义一个支持加法的协议,用协变/逆变类型变量关联输入和输出类型,让类型系统自动推断结果:
from typing import TypeVar, Protocol, Generic, Union from decimal import Decimal from fractions import Fraction # 定义逆变的输入类型和协变的输出类型 T_contra = TypeVar('T_contra', contravariant=True) T_co = TypeVar('T_co', covariant=True) class SupportsAdd(Protocol[T_contra, T_co]): """支持加法操作的协议,输入T_contra类型,返回T_co类型""" def __add__(self, other: T_contra) -> T_co: ... # 限定Number的泛型参数为支持的数值类型 T = TypeVar('T', int, float, Decimal, Fraction) # 结果类型变量,由类型检查器自动推断 R = TypeVar('R', int, float, Decimal, Fraction) class Number(Generic[T]): value: T def __add__(self, other: Union[T, "Number[T]", SupportsAdd[T, R]]) -> Number[R]: other_val = other.value if isinstance(other, Number) else other result_val = self.value + other_val return Number(value=result_val)
此方案通过协议描述加法的类型关系,类型检查器会根据T和other的类型自动推断结果类型R,无需手动列举所有组合,扩展性更强。
方案3:利用类型检查器的内置推断(简洁版)
如果不需要极致的精确性,可以直接利用类型检查器对Python内置数值类型加法的支持,简化类型标注:
from typing import TypeVar, Generic, Union, Any from decimal import Decimal from fractions import Fraction T = TypeVar('T', int, float, Decimal, Fraction) class Number(Generic[T]): value: T def __add__(self, other: Union[T, int, float, Decimal, Fraction, "Number[Any]"]) -> "Number": other_val = other.value if isinstance(other, Number) else other result_val = self.value + other_val return Number(value=result_val)
这里返回类型写Number(不带泛型参数),类型检查器会自动根据实际运算结果推断具体的泛型类型,比如Number[int] + 3.14会被识别为返回Number[float]。
内容的提问来源于stack exchange,提问作者Dait
相关产品推荐
相关产品推荐

