You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何为支持重叠Union类型的函数/方法参数添加类型标注?

Solution for PyRight Type Checking with Mixed Numeric Types

First, define your core type aliases clearly:

import typing as tp
from fractions import Fraction
from decimal import Decimal

# Define valid type groups
Real = tp.Union[int, float, Fraction]
DecLike = tp.Union[int, Decimal]

1. Generic Class with Constrained TypeVar

For class-based implementations, use a constrained TypeVar to enforce that instance methods only accept compatible types. This eliminates type checker errors for no-arg methods and ensures type consistency across operations.

# TypeVar constrained to either Real or DecLike groups
T = tp.TypeVar("T", Real, DecLike)

class Numeric(tp.Generic[T]):
    def __init__(self, value: T) -> None:
        self.value: T = value

    def add(self, other: T) -> "Numeric[T]":
        # Runtime validation matching your existing logic
        has_decimal = isinstance(self.value, Decimal) or isinstance(other, Decimal)
        if has_decimal:
            if not isinstance(self.value, (int, Decimal)) or not isinstance(other, (int, Decimal)):
                raise TypeError("Cannot mix Decimal with non-int/non-Decimal types")
        else:
            if not isinstance(self.value, (int, float, Fraction)) or not isinstance(other, (int, float, Fraction)):
                raise TypeError("Invalid type for Real number operation")
        
        # PyRight recognizes this operation is safe since T is a single valid group
        return Numeric(self.value + other)

    # No-arg method works seamlessly with the generic type
    def get_value(self) -> T:
        return self.value

2. TypeGuard for Standalone Functions

For standalone functions, use TypeGuard to narrow types after runtime checks. This tells PyRight exactly what type variables are after validation, eliminating false positive errors about unsupported operations.

# TypeGuard functions to validate membership in valid type groups
def is_real(x: tp.Any) -> tp.TypeGuard[Real]:
    return isinstance(x, (int, float, Fraction))

def is_declike(x: tp.Any) -> tp.TypeGuard[DecLike]:
    return isinstance(x, (int, Decimal))

def add(a: tp.Union[Real, DecLike], b: tp.Union[Real, DecLike]) -> tp.Union[Real, DecLike]:
    # Check if we're dealing with Decimal-compatible types
    if isinstance(a, Decimal) or isinstance(b, Decimal):
        if not (is_declike(a) and is_declike(b)):
            raise TypeError("Cannot mix Decimal with non-int/non-Decimal types")
        return a + b  # PyRight confirms a/b are DecLike here
    else:
        if not (is_real(a) and is_real(b)):
            raise TypeError("Invalid type for Real number operation")
        return a + b  # PyRight confirms a/b are Real here

3. Function Overloads (Standalone Use)

If you prefer explicit signatures, define overloads for each valid type group. This avoids flattened union confusion and lets PyRight infer correct types at check time.

@tp.overload
def add(a: Real, b: Real) -> Real: ...

@tp.overload
def add(a: DecLike, b: DecLike) -> DecLike: ...

def add(a: tp.Union[Real, DecLike], b: tp.Union[Real, DecLike]) -> tp.Union[Real, DecLike]:
    # Same runtime validation as before
    has_decimal = isinstance(a, Decimal) or isinstance(b, Decimal)
    if has_decimal:
        if not isinstance(a, (int, Decimal)) or not isinstance(b, (int, Decimal)):
            raise TypeError("Cannot mix Decimal with non-int/non-Decimal types")
    else:
        if not isinstance(a, (int, float, Fraction)) or not isinstance(b, (int, float, Fraction)):
            raise TypeError("Invalid type for Real number operation")
    return a + b

Key Benefits

  • Generic Class: The constrained TypeVar ensures all operations use types from a single valid group, so PyRight never encounters incompatible combinations.
  • TypeGuard: Explicit type narrowing removes false positives by letting the checker know exactly what types are valid after runtime checks.
  • Overloads: Clear signatures for valid type pairs enable PyRight to reject invalid combinations during static analysis.

Content of the question comes from Stack Exchange, asked by I Like Python

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.20 12:24:56