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

如何在Python的Generic类中实现可选TypeVar以简化装饰器类型定义?

实现带默认泛型参数的装饰器协议

解决方案:用类型别名+重载实现简洁使用

Python的Generic目前不支持直接将第二个类型变量默认绑定到第一个,但可以通过**类型别名+@overload**的组合实现你想要的简洁写法,同时完全保留Mypy的类型校验能力。

步骤1:保留基础协议定义

先维持原本的双泛型参数协议,确保类型转换类装饰器的场景依然可用:

from typing import Protocol, TypeVar, Generic, Callable, overload

TIn = TypeVar('TIn', contravariant=True)
TOut = TypeVar('TOut', covariant=True)

class _DecoratorProtocol(Protocol, Generic[TIn, TOut]):
    """内部基础协议,不直接对外暴露"""
    def __call__(self, value: TIn) -> TOut:
        ...

步骤2:定义重载的类型入口

通过@overload为Decorator提供两种使用形式:一种是仅传入TIn(自动让TOut=TIn),另一种是传入两个泛型参数:

@overload
def Decorator[T]() -> type[_DecoratorProtocol[T, T]]: ...

@overload
def Decorator[TIn, TOut]() -> type[_DecoratorProtocol[TIn, TOut]]: ...

def Decorator(*args, **kwargs):
    # 运行时无实际逻辑,仅用于类型注解
    raise NotImplementedError("Decorator仅用于类型标注,不可实例化")

步骤3:简洁使用示例

现在你可以像预期的那样简化装饰器的返回类型标注,Mypy会自动推断TOut=TIn:

IntFunction = Callable[[int, int], int]

def register_operator(op: str) -> Decorator[IntFunction]:
    def inner(value: IntFunction) -> IntFunction:
        # 注册逻辑
        return value
    return inner

@register_operator("+")
def add(a: int, b: int) -> int:
    return a + b

类型转换场景依然兼容

当需要不同的输入输出类型时,依然可以传入两个泛型参数,不影响原有功能:

StrFunction = Callable[[int, int], str]

def stringify_operator(op: str) -> Decorator[IntFunction, StrFunction]:
    def inner(value: IntFunction) -> StrFunction:
        def wrapper(a: int, b: int) -> str:
            return f"{a} {op} {b} = {value(a, b)}"
        return wrapper
    return inner

@stringify_operator("*")
def multiply(a: int, b: int) -> int:
    return a * b

# Mypy会自动校验multiply的输入是否符合IntFunction,返回是否符合StrFunction

原写法失效的原因

Python泛型类不支持将第二个类型变量的默认值设为第一个类型变量(TOut=TIn),这是当前类型系统的限制——类型变量的默认值必须是具体类型或无,不能依赖其他类型变量。


内容的提问来源于stack exchange,提问作者Maddy Guthridge

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.05 08:30:18