带有 numpy ndarray 和 pandas 数据框的 mypy 重载函数(签名参数类型相同或更广泛)

mypy overload function with numpy ndarray and pandas dataframe (signature parameter type(s) are the same or broader)

我有一个函数可以对 numpy 数组或 pandas 数据帧执行一些算术运算(分位数归一化)。当你放入一个 ndarray 时,你应该得到一个 ndarray,当你放入一个 pandas 数据帧时,你应该得到一个数据帧:

from typing import Union, overload


@overload
def quantile_normalize(data: pd.DataFrame) -> pd.DataFrame: ...
@overload
def quantile_normalize(data: np.ndarray) -> np.ndarray: ...


def quantile_normalize(data: Union[pd.DataFrame, np.ndarray]) -> Union[pd.DataFrame, np.ndarray]:
    pass

然而,当我尝试用 mypy 测试它时,它会抱怨:

qnorm/quantile_normalize.py:72: error: Overloaded function signature 2 will never be matched: signature 1's parameter type(s) are the same or broader

到目前为止我发现的与此问题相关的问题和答案似乎都与可选的 input/output 和 None 类型有关。 pandas dataframe 和 numpy array 是相关的,但是,它们应该可以被 mypy 区分。

当库缺少类型提示时,每次导入都将解析为 Anynumpypandas 都不符合 PEP 526(不提供任何类型提示)并且在 typeshed 中没有存根,因此 pd.DataFramenp.ndarray 都将解析为 Any,因此两个重载都解析为 def quantile_normalize(data: Any) -> Any: ...。要解决此问题,请为 numpypandas 添加存根。

要么使用现有的类型存根 - 我使用 data-science-types (PyPI, GitHub) 为 numpypandasmatplotlib:[=32 提供存根=]

$ pip install data-science-types

现在 pd.DataFramenp.ndarray 将在 运行 宁 mypy 时正确解析。这还将免费为您提供支持 PEP 526(例如 Visual Studio Code 或 WingIDE)的每个 IDE 中更好的代码补全。

或者,如果您t/don不想添加存根包,请编写您自己的最小存根,例如

# _typeshed/pandas/__init__.pyi

from typing import Any


def __getattr__(name: str) -> Any: ...  # incomplete

class DataFrame:
    def __getattr__(self, name: str) -> Any: ...  # incomplete

# _typeshed/numpy/__init__.pyi

from typing import Any


def __getattr__(name: str) -> Any: ...  # incomplete

class ndarray:
    def __getattr__(self, name: str) -> Any: ...  # incomplete

和运行 MYPYPATH=_typeshed mypy ....