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

运行时可检查协议联合类型别名触发mypy实例检查错误问题

问题:Runtime-Checkable Protocol联合类型别名触发mypy泛型错误

问题场景

用户定义了一个联合类型别名_ConvertibleToInt,将SupportsInt、SupportsIndex和自定义的@runtime_checkable修饰的SupportsTrunc Protocol合并:

from typing import Protocol, runtime_checkable, SupportsInt, SupportsIndex

@runtime_checkable
class SupportsTrunc(Protocol):
    def __trunc__(self) -> int: ...

_ConvertibleToInt = SupportsInt | SupportsIndex | SupportsTrunc

但执行isinstance(o, _ConvertibleToInt)检查时,mypy触发错误:

Parameterized generics cannot be used with class or instance checks

但以下两种场景无错误:

  • 直接在isinstance中写完整联合类型:isinstance(o, SupportsInt | SupportsIndex)
  • 仅给单个Protocol起别名,比如MyProto = SupportsInt后执行isinstance(o, MyProto)

另外,重复同一Protocol的联合别名(如SupportsInt | SupportsInt)也会触发相同错误。用户确认所有Protocol均为@runtime_checkable,并非参数化泛型。

原因分析

这是mypy的已知bug,问题出在联合类型别名的处理逻辑漏洞:

  • 当联合类型别名包含多个@runtime_checkable的Protocol时,mypy会错误地将其识别为参数化泛型(实际并非如此)
  • 重复同一Protocol的联合也会触发bug,因为mypy处理联合类型去重时逻辑出错,误判为泛型类型

临时解决办法

  1. 直接写完整联合类型:跳过别名,直接在isinstance中使用isinstance(o, SupportsInt | SupportsIndex | SupportsTrunc)
  2. 合并为新的Runtime-Checkable Protocol:
@runtime_checkable
class ConvertibleToInt(Protocol):
    def __int__(self) -> int: ...
    def __index__(self) -> int: ...
    def __trunc__(self) -> int: ...

(注:此方式要求实例同时实现三个方法,若需要“满足任意一个即可”的逻辑,建议用下方TypeGuard方案)
3. 用TypeGuard自定义检查函数:

from typing import TypeGuard

def is_convertible_to_int(o: object) -> TypeGuard[SupportsInt | SupportsIndex | SupportsTrunc]:
    return isinstance(o, (SupportsInt, SupportsIndex, SupportsTrunc))

之后用if is_convertible_to_int(o):替代原isinstance检查,mypy可正确识别类型。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.03 15:33:28