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

如何为要求首参为Iterable的Python装饰器添加正确类型注解?

解决装饰器类型注解的逆变问题

错误原因分析

你遇到的问题确实是Callable参数的逆变特性导致的:Callable的参数类型是逆变的——如果装饰器期望接收一个参数类型为Iterable[int]的函数,只有参数类型比Iterable[int]更宽泛的函数(比如接受object)才能适配;而list[int]是Iterable[int]的子类型(更具体),所以无法满足原装饰器的类型要求。

正确的类型注解写法

我们需要通过泛型约束让装饰器接受任意Iterable的子类型作为第一个参数,而非固定死Iterable[int]。修改后的代码如下:

from typing import Callable, Concatenate, Iterable, ParamSpec, TypeVar

# 定义受约束的类型变量,代表任意Iterable的子类型
T = TypeVar("T", bound=Iterable[object])
P = ParamSpec("P")
R = TypeVar("R")

def printcontent(f: Callable[Concatenate[T, P], R]) -> Callable[Concatenate[T, P], R]:
    def func(xs: T, *args: P.args, **kwargs: P.kwargs) -> R:
        for x in xs:
            print(x)
        return f(xs, *args, **kwargs)
    return func

@printcontent
def mysum(xs: list[int]) -> int:
    return sum(xs)

# 测试其他Iterable类型也能正常工作
@printcontent
def count_chars(s: str) -> int:
    return len(s)

说明

  • T = TypeVar("T", bound=Iterable[object]):约束T必须是Iterable的子类型,确保装饰器可以接受任何实现迭代协议的类型(list、str、tuple等)作为第一个参数。
  • 装饰函数时,泛型参数T会自动推断为具体类型(比如list[int]或str),既适配被装饰函数的参数类型,又满足装饰器遍历第一个参数的逻辑。

这样修改后,Mypy就能正常通过类型检查,同时保留装饰器的原有功能。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.16 14:25:04