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

如何用Python 3.12语法为偏应用实现类型标注?

自定义simple_partial类的Python 3.12类型标注方案

问题背景

需要为自定义的偏应用类simple_partial添加类型标注,优先使用Python 3.12语法。该类实现了类似functools.partial的功能,但之前的两种标注方案存在问题:

  • 方案1:未区分__init__与__call__的参数差异,类型检查无法识别偏应用的参数拆分逻辑。
  • 方案2:尝试使用两个ParamSpec但因Concatenate用法错误失效(旧写法不支持直接拼接多个ParamSpec)。

正确的类型标注实现

利用Python 3.12对ParamSpec和Concatenate的增强支持,可准确标注simple_partial的参数传递逻辑:

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

T = TypeVar('T')
PInit = ParamSpec('PInit')
PCall = ParamSpec('PCall')

class simple_partial[T, **PInit, **PCall]:
    def __init__(
        self,
        f: Callable[Concatenate[Unpack[PInit], Unpack[PCall]], T],
        *args: Unpack[PInit.args],
        **kwargs: Unpack[PInit.kwargs]
    ) -> None:
        self.f = f
        self.args = args
        self.kwargs = kwargs

    def __call__(
        self,
        *args: Unpack[PCall.args],
        **kwargs: Unpack[PCall.kwargs]
    ) -> T:
        return self.f(*(*self.args, *args), **(self.kwargs | kwargs))

# 测试代码
partially = simple_partial(lambda x, y, z=3: (x, y, z), 1)
partially(2)  # 类型检查会提示接受y参数和可选z参数,返回tuple[int, int, int]

方案说明

  1. 类型变量定义:
    • T:表示原函数的返回值类型。
    • PInit:表示__init__时传入的部分参数的参数规格。
    • PCall:表示__call__时传入的剩余参数的参数规格。
  2. 原函数类型约束:
    • 原函数f的参数是PInit和PCall的拼接,通过Concatenate[Unpack[PInit], Unpack[PCall]]实现参数序列的合并。
  3. 方法参数标注:
    • __init__接收PInit对应的位置参数和关键字参数,用Unpack展开参数规格。
    • __call__接收PCall对应的剩余参数,同样用Unpack展开,确保类型检查能识别偏应用后需要传入的参数。

之前方案失效原因

  • 方案1:使用单一ParamSpec导致__init__和__call__都要求传入完整的原函数参数,违背了偏应用“拆分参数传递”的核心逻辑。
  • 方案2:错误地直接将两个ParamSpec传入Concatenate,正确写法需用Unpack分别展开参数规格后再拼接,该特性在Python 3.12中才支持。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.17 11:03:22