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

Mypy报错:重载函数签名重叠且返回类型不兼容,求解决方案

问题描述

我希望自定义类的__getitem__重载方法,根据传入参数为str或Sequence[str]时,分别返回单个float或float序列。使用Python内置typing模块的@overload装饰器定义了两个重载方法及一个实现方法后,mypy在第一个重载方法行报错:"Overloaded function signatures 1 and 2 overlap with incompatible return types"。推测原因是str被识别为Sequence[str]导致歧义。

代码如下:

class SimulationResults:
    ...

    # Mypy error occurs here
    @overload
    def __getitem__(self: Self, names: str) -> float:
        ...

    @overload
    def __getitem__(self: Self, names: Sequence[str]) -> Sequence[float]:
        ...

    def __getitem__(self: Self, names: str | Sequence[str]) -> float | Sequence[float]:
        def get_value(name: str) -> float:
            if name == self._time_var_name:
                return self._time[self._current_index]

            if name not in self._vars:
                raise KeyError(f"Variable '{name}' does not exist for this simulation")

            return self._vars[name][self._current_index]

        return (
            get_value(names)
            if isinstance(names, str)
            else tuple(get_value(name) for name in names)
        )
报错原因

没错,问题出在str本身就是Sequence[str]的子类(Python中字符串属于字符序列)。mypy检测到当传入str类型参数时,两个重载签名都能匹配,但返回类型一个是float、一个是Sequence[float],类型不兼容,因此抛出重叠报错。

解决办法

方案1:使用排除字符串的序列类型(Python 3.10+)

利用typing.NotStrSequence(专门排除str的序列类型)来明确第二个重载的参数范围,消除歧义:

from typing import Self, Sequence, overload, NotStrSequence

class SimulationResults:
    ...

    @overload
    def __getitem__(self: Self, names: str) -> float:
        ...

    @overload
    def __getitem__(self: Self, names: NotStrSequence[str]) -> Sequence[float]:
        ...

    def __getitem__(self: Self, names: str | NotStrSequence[str]) -> float | Sequence[float]:
        # 原实现代码不变
        def get_value(name: str) -> float:
            if name == self._time_var_name:
                return self._time[self._current_index]

            if name not in self._vars:
                raise KeyError(f"Variable '{name}' does not exist for this simulation")

            return self._vars[name][self._current_index]

        return (
            get_value(names)
            if isinstance(names, str)
            else tuple(get_value(name) for name in names)
        )

如果使用低于3.10的Python版本,可以自行定义排除str的序列类型:

from typing import Self, Sequence, overload, TypeVar
from collections.abc import Sequence as ABCSequence

# 定义仅匹配非str的字符串序列类型
NonStrSequenceStr = TypeVar('NonStrSequenceStr', bound=ABCSequence[str])

class SimulationResults:
    ...

    @overload
    def __getitem__(self: Self, names: str) -> float:
        ...

    @overload
    def __getitem__(self: Self, names: NonStrSequenceStr) -> Sequence[float]:
        ...

    def __getitem__(self: Self, names: str | NonStrSequenceStr) -> float | Sequence[float]:
        # 原实现代码不变
        ...

方案2:拆分方法,规避重载歧义

放弃在__getitem__中做重载,改为提供两个独立方法分别处理单字符串和序列场景,同时保留__getitem__作为统一入口:

from typing import Self, Sequence

class SimulationResults:
    ...

    def _get_single_value(self, name: str) -> float:
        if name == self._time_var_name:
            return self._time[self._current_index]
        if name not in self._vars:
            raise KeyError(f"Variable '{name}' does not exist for this simulation")
        return self._vars[name][self._current_index]

    def get(self, name: str) -> float:
        return self._get_single_value(name)
    
    def get_many(self, names: Sequence[str]) -> Sequence[float]:
        return tuple(self._get_single_value(name) for name in names)
    
    def __getitem__(self, names: str | Sequence[str]) -> float | Sequence[float]:
        if isinstance(names, str):
            return self.get(names)
        return self.get_many(names)

这种方式逻辑更清晰,也彻底避免了类型重载的歧义问题。

方案3:使用类型守卫辅助mypy识别(结合参数类型调整)

自定义类型守卫函数,帮助mypy更精准判断参数类型,同时配合调整重载的参数范围:

from typing import Self, Sequence, overload, TypeGuard
from typing import NotStrSequence

def is_single_name(names: str | NotStrSequence[str]) -> TypeGuard[str]:
    return isinstance(names, str)

class SimulationResults:
    ...

    @overload
    def __getitem__(self: Self, names: str) -> float:
        ...

    @overload
    def __getitem__(self: Self, names: NotStrSequence[str]) -> Sequence[float]:
        ...

    def __getitem__(self: Self, names: str | NotStrSequence[str]) -> float | Sequence[float]:
        def get_value(name: str) -> float:
            if name == self._time_var_name:
                return self._time[self._current_index]
            if name not in self._vars:
                raise KeyError(f"Variable '{name}' does not exist for this simulation")
            return self._vars[name][self._current_index]

        if is_single_name(names):
            return get_value(names)
        return tuple(get_value(name) for name in names)

类型守卫能让mypy在类型检查时更准确地关联参数和返回类型,配合NotStrSequence可以彻底消除歧义。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.13 07:57:09