Python 重载单个参数

Gre*_*urm 6 python overloading python-typing

假设我有一个带有许多参数的函数,例如

import pandas as pd

def f(df: pd.DataFrame, a: int, b: int, c: int, d: int, inplace: bool = True) -> Optional[pd.DataFrame]:
    raise NotImplementedError
Run Code Online (Sandbox Code Playgroud)

该函数将修改数据帧 ifinplace=True并返回修改后的副本 if inplace=False

我知道我能做到

@overload
def f(df: pd.DataFrame, a: int, b: int, c: int, d: int, inplace: Literal[True] = True) -> None:
    ...

@overload
def f(df: pd.DataFrame, a: int, b: int, c: int, d: int, inplace: Literal[False] = True) -> pd.DataFrame:
    ...
Run Code Online (Sandbox Code Playgroud)

通知打字系统这一事实。

但是,我想知道是否有一种方法可以在不重复整个函数定义的情况下执行此操作,如果有很多参数,这似乎很麻烦。我正在寻找类似的东西

@overload
def f(..., inplace: Literal[True]) -> None:
    ...

@overload
def f(..., inplace: Literal[False]) -> pd.DataFrame:
    ...
Run Code Online (Sandbox Code Playgroud)

编辑:有几个人指出 API 设计本身可能存在缺陷。虽然这可能是真的,但在这种特殊情况下,我回顾性地将类型提示添加到现有库中,并且无法更改接口。

che*_*ner 3

一个带有布尔标志来改变其行为的函数是一种反模式。应该有两个函数:一个函数就地修改并返回None,另一个函数返回修改后的副本。(参见list.sortsorted。)

这并不意味着您需要重复行为;而是意味着您需要重复行为。它只是意味着其中一个函数将是另一个函数的薄包装。

import pandas as pd


def inplace_f(df: pd.DataFrame, a: int, b: int, c: int, d: int) -> None:
    ...


def f(df: pd.DataFrame, a: int, b: int, c: int, d:int) -> pd.DataFrame:
    copy = df.copy()
    inplace_f(copy)
    return copy
Run Code Online (Sandbox Code Playgroud)

现在,您只需使用前一个布尔参数来决定使用哪个函数。也就是说,例如,

f(df, ..., inplace)
Run Code Online (Sandbox Code Playgroud)

变成

(inplace_f if inplace else f)(df, ...)
Run Code Online (Sandbox Code Playgroud)

如果您的反对意见是这比“简单”调用更复杂,那么您就忽略了“简单”调用并不那么简单的事实,因为如果您不这样f做,那么调用显然没有意义inplace=False对返回值做任何事情。上下文已经意味着您对 的值有所了解inplace,因此选择正确的函数并不比为同一函数提供布尔参数更困难。

  • “一个带有布尔标志来改变其行为的函数是一种反模式。” 将整个“pandas”库扔到公共汽车下?我并不是说这是黄金标准,但这是一种普遍的模式 (3认同)