Python: 为什么在函数中使用重载而不是 *args (尤其是当参数类型不影响函数运行方式时)

Python: why use overloading instead of *args in a function (especially when the type of arguments do not affect how the function runs)

已编辑: 我正在查看内置 zip() 函数的类型注释。

我知道重载(在类型检查的上下文中)可以根据给定的参数类型修改函数的行为。

    @overload
    def zip(__iter1: Iterable[_T1]) -> List[Tuple[_T1]]: ...
    @overload
    def zip(__iter1: Iterable[_T1],
            __iter2: Iterable[_T2]) -> List[Tuple[_T1, _T2]]: ...
    @overload
    def zip(__iter1: Iterable[_T1], __iter2: Iterable[_T2],
            __iter3: Iterable[_T3]) -> List[Tuple[_T1, _T2, _T3]]: ...
    @overload
    def zip(__iter1: Iterable[_T1], __iter2: Iterable[_T2], __iter3: Iterable[_T3],
            __iter4: Iterable[_T4]) -> List[Tuple[_T1, _T2, _T3, _T4]]: ...
    @overload
    def zip(__iter1: Iterable[_T1], __iter2: Iterable[_T2], __iter3: Iterable[_T3],
            __iter4: Iterable[_T4], __iter5: Iterable[_T5]) -> List[Tuple[_T1, _T2, _T3, _T4, _T5]]: ...
    @overload
    def zip(__iter1: Iterable[Any], __iter2: Iterable[Any], __iter3: Iterable[Any],
            __iter4: Iterable[Any], __iter5: Iterable[Any], __iter6: Iterable[Any],
            *iterables: Iterable[Any]) -> List[Tuple[Any, ...]]: ...
  1. 但是,在本例中,类型是相同的 (Any)。那么超载的目的是什么?

  2. 为什么不只使用最后一个函数,它接受任意数量的参数。为什么要创建前五个,其本质上是说:如果有一个参数,则执行此操作,如果有两个,则执行该操作,如果有 3 个... 这似乎违反了DRY原则。

    @overload
    def zip(__iter1: Iterable[Any], __iter2: Iterable[Any], __iter3: Iterable[Any],
            __iter4: Iterable[Any], __iter5: Iterable[Any], __iter6: Iterable[Any],
            *iterables: Iterable[Any]) -> List[Tuple[Any, ...]]: ...

这是一个优化。可以处理任意数量参数的版本需要使用额外的循环级别。固定数量参数的版本可以硬编码访问每个参数,这样效率更高。

zip() 的绝大多数用途只有 2-3 个参数,因此尽管这种优化可能很小,但加起来却非常有益。

overload装饰器用于静态类型分析,不用于实现。事实上,问题中显示的代码只是类型注释 - zip 是内置的,未在 Python.

中实现

各种重载的目的是保留参数的数量和类型。例如,它指出 zip 超过三个可迭代对象会产生具有三个与可迭代元素类型匹配的元素的元组。可变参数 *argsAny 的最终重载只是未指定情况的包罗万象。