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

如何实现输入输出类型一一对应的Python函数自动重载?

如何自动重载输入输出类型一一对应的函数?

我有一类函数,它们的返回类型与单个输入的类型存在严格的一一对应关系。比如下面这个函数:

from typing import reveal_type

def func(x: str | list[str]) -> int | list[int]:
    """
    Some docstring that should show up.
    """
    if isinstance(x, str):
        return 0
    return list(range(len(x)))

y = func(["hi", "hello"])
reveal_type(y)  # 类型显示为 int | list[int]

直接使用联合类型标注输入输出时,IDE或类型检查器会把y的类型推断为int | list[int],但实际上传入list[str]时返回的必然是list[int],类型提示不够精确。

为了获得精确的类型提示,我们可以手动用@overload装饰器实现重载:

from typing import overload, reveal_type

@overload
def func(x: str) -> int: ...

@overload
def func(x: list[str]) -> list[int]: ...

def func(x: str | list[str]) -> int | list[int]:
    """
    Some docstring that should show up.
    """
    if isinstance(x, str):
        return 0
    return list(range(len(x)))

y = func(["hi", "hello"])
reveal_type(y)  # 类型显示为 list[int]

这样y的类型就能被精确推断为list[int]了,但我有很多这类函数,手动写重载会非常繁琐。我希望能有一种更简洁的方式,比如假设存在UnionMatch类型:

from typing import UnionMatch  # 仅为示例,实际不存在

def func(x: UnionMatch[str, list[str]]) -> UnionMatch[int, list[int]]:
    """
    Some docstring that should show up.
    """
    if isinstance(x, str):
        return 0
    return list(range(len(x)))

无需手动编写@overload,就能让类型检查器自动对应输入输出的类型关系。

现有方案的问题

有人针对两种类型的场景提供了一个基于泛型类的解决方案,但存在两个致命问题:

  • 函数的文档字符串会丢失,IDE中悬停查看时只能看到泛型类的类型信息,看不到原函数的文档;
  • 仅支持两种类型的对应,无法扩展到三种及以上的类型场景。

该方案的代码如下:

from typing import (
    reveal_type,
    Callable,
    Concatenate,
    Generic,
    overload,
    ParamSpec,
    TypeVar,
)

_C1 = TypeVar("_C1")
_C2 = TypeVar("_C2")
_P = ParamSpec("_P")
_T1 = TypeVar("_T1")
_T2 = TypeVar("_T2")

class FuncTemplate(Generic[_C1, _C2, _P, _T1, _T2]):

    def __init__(self, func: Callable[Concatenate[_C1 | _C2, _P], _T1 | _T2]) -> None:
        self.func = func
        # self.__call__.__doc__ = func.__doc__
        # 此写法无效,会报错:AttributeError: attribute '__doc__' of 'method' objects is not writable

    @overload
    def __call__(
        self,
        common_input: _C1,
        *args: _P.args,
        **kwargs: _P.kwargs,
    ) -> _T1: ...

    @overload
    def __call__(
        self,
        common_input: _C2,
        *args: _P.args,
        **kwargs: _P.kwargs,
    ) -> _T2: ...

    def __call__(
        self,
        common_input: _C1 | _C2,
        *args: _P.args,
        **kwargs: _P.kwargs,
    ) -> _T1 | _T2:
        return self.func(common_input, *args, **kwargs)

@FuncTemplate
def func(x: str | list[str]) -> int | list[int]:
    """
    Some docstring that should show up.
    """
    if isinstance(x, str):
        return 0
    return list(range(len(x)))

y = func(["hi", "hello"])
reveal_type(y)  # list[int]

z = func("hey")
reveal_type(z)  # int

在IDE中悬停查看func时,显示的内容是(function) func: FuncTemplate[str, list[str], (), int, list[int]],完全看不到原函数的文档字符串。

请问如何实现支持多类型对应且保留文档字符串的自动重载功能?


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.21 14:04:53