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

Python泛型TypeVar应用:装饰器自动绑定Task泛型类型问题

问题描述

我正在构建一个适配Python typing的类装饰器,现有代码如下:

from typing import TypeVar, Generic, List, Type

ExecutorType = TypeVar("ExecutorType")

class Task(Generic[ExecutorType]):
    _executor: ExecutorType

    pass

TaskType = TypeVar("TaskType", bound=Task)
ChildTaskType = TypeVar("ChildTaskType", bound=Task)
ExecutorType = TypeVar("ExecutorType", bound='Executor')

class Executor(Generic[TaskType]):
    _TASKS_CLASSES: List[Type[TaskType]] = []

    @classmethod
    def task(cls: Type[ExecutorType]):
        def decorator(task_cls: Type[ChildTaskType]):
            cls._TASKS_CLASSES.append(task_cls)
            return task_cls
        return decorator
    
class Checker(Executor):
    def checker_method(self):
        return "Check Method"
    pass

我希望无类型错误地编写如下装饰器代码:

@Checker.task()
class Check(Task):
    def check_method(self):
        self._executor.checker_method()

但此时self._executor被推断为基类Executor类型,而非Checker,导致checker_method无法被识别。手动指定Task[Checker]可以解决该问题,但我想知道能否通过装饰器task的类型注解,让返回的类自动将泛型参数指定为当前的ExecutorType(即实现类似返回Type[ChildTaskType[ExecutorType]]的效果)。

解决方案

要实现这个需求,需要调整泛型参数的定义和装饰器的类型注解,让Executor和Task的泛型参数形成关联。修改后的代码如下:

from typing import TypeVar, Generic, List, Type, cast

# 重新定义泛型参数,明确边界和关联关系
T_Executor = TypeVar("T_Executor", bound="Executor")
T_Task = TypeVar("T_Task", bound="Task")

class Task(Generic[T_Executor]):
    _executor: T_Executor

class Executor(Generic[T_Task]):
    _TASKS_CLASSES: List[Type[T_Task]] = []

    @classmethod
    def task(cls: Type[T_Executor]):
        def decorator(task_cls: Type[Task[object]]) -> Type[Task[T_Executor]]:
            # 用cast告诉类型检查器,返回的Task类的泛型参数是当前Executor类型
            annotated_task_cls = cast(Type[Task[T_Executor]], task_cls)
            cls._TASKS_CLASSES.append(annotated_task_cls)
            return annotated_task_cls
        return decorator
    
class Checker(Executor):
    def checker_method(self) -> str:
        return "Check Method"

# 现在使用装饰器时,无需手动指定Task[Checker]
@Checker.task()
class Check(Task):
    def check_method(self) -> None:
        # self._executor会被正确推断为Checker类型
        self._executor.checker_method()

关键改动说明:

  • 重命名泛型参数(如T_Executor、T_Task)避免重复定义,增强可读性
  • 在装饰器内部,通过cast将传入的Task类强制标注为绑定当前ExecutorType的泛型类,让类型检查器能够正确推断self._executor的类型
  • 调整Executor的泛型参数关联,确保_TASKS_CLASSES存储的是绑定了对应Executor类型的Task子类

这样修改后,Check类无需手动指定Task[Checker],self._executor会自动被推断为Checker类型,checker_method可以正常被识别,且不会出现类型错误。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.21 16:52:32