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

使用字典推导与isinstance时mypy报返回值类型不兼容错误求助

MyPy类型错误修复:返回值类型不兼容问题

错误信息

Incompatible return value type (got "Dict[str, Pin]", expected "Union[Dict[str, Input], Dict[str, Output]]")  [return-value]mypy

示例代码

from typing import Dict, List, Union, Type

class Pin():
    def __init__(self):
        pass

class Input(Pin):
    def __init__(self):
        pass

class Output(Pin):
    def __init__(self):
        pass

INPUT_STRINGS: List[str] = ["in", "input", "i"]
OUTPUT_STRINGS: List[str] = ["out", "output", "o"]

def filter_pins(pins: Dict[str, Pin], which) -> Union[Dict[str, Input], Dict[str, Output]]:
        direction: Union[Type[Output], Type[Input]]
        if which.lower() in OUTPUT_STRINGS:
            direction = Output
        elif which.lower() in INPUT_STRINGS:
            direction = Input
        filtered = {name: pin for name, pin in pins.items() if isinstance(pin, direction)}
        return filtered

问题原因

MyPy无法在字典推导的上下文中,对direction这个Union类型变量做精确的类型收窄。尽管你已经通过条件分支给direction赋值了具体的子类,但MyPy在处理字典推导时,仍然把direction当成Union[Type[Input], Type[Output]]看待,因此无法推断出筛选后的pin必然是Input或Output实例,只能识别为父类Pin,导致返回的字典类型与声明的返回值类型不匹配。这属于MyPy对复杂上下文类型推断的限制,并非Bug。

修复方案

方案1:拆分逻辑到条件分支(推荐)

将字典推导放到对应的if/elif分支中,让MyPy能明确每个分支返回的具体字典类型:

from typing import Dict, List, Union, Type

class Pin():
    def __init__(self):
        pass

class Input(Pin):
    def __init__(self):
        pass

class Output(Pin):
    def __init__(self):
        pass

INPUT_STRINGS: List[str] = ["in", "input", "i"]
OUTPUT_STRINGS: List[str] = ["out", "output", "o"]

def filter_pins(pins: Dict[str, Pin], which: str) -> Union[Dict[str, Input], Dict[str, Output]]:
    which_lower = which.lower()
    if which_lower in OUTPUT_STRINGS:
        return {name: pin for name, pin in pins.items() if isinstance(pin, Output)}
    elif which_lower in INPUT_STRINGS:
        return {name: pin for name, pin in pins.items() if isinstance(pin, Input)}
    # 处理非法输入的默认分支
    raise ValueError(f"Invalid direction: {which}")

每个分支直接使用具体的子类进行筛选,MyPy能准确推断返回的字典类型,完全符合声明的返回值要求。

方案2:使用类型强制转换

如果不想拆分逻辑,可以用typing.cast手动向MyPy断言筛选后的字典类型:

from typing import Dict, List, Union, Type, cast

# 类定义部分不变

def filter_pins(pins: Dict[str, Pin], which: str) -> Union[Dict[str, Input], Dict[str, Output]]:
    direction: Union[Type[Output], Type[Input]]
    which_lower = which.lower()
    if which_lower in OUTPUT_STRINGS:
        direction = Output
        filtered = cast(Dict[str, Output], {name: pin for name, pin in pins.items() if isinstance(pin, direction)})
    elif which_lower in INPUT_STRINGS:
        direction = Input
        filtered = cast(Dict[str, Input], {name: pin for name, pin in pins.items() if isinstance(pin, direction)})
    else:
        raise ValueError(f"Invalid direction: {which}")
    return filtered

注意:使用cast相当于手动跳过MyPy的类型检查,需确保业务逻辑绝对正确,避免引入类型安全隐患。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.03 13:50:40