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

Python自定义类型APINullable不被MyPy及主流IDE识别问题求助

问题描述

我正在尝试实现一些自定义类型,但我的IDE和MyPy均无法正确识别该类型。

以下是代码片段:

from typing import Union


class MissingType(type):
    ...


MISSING = MissingType


class APINullable(type):
    @staticmethod
    def __class_getitem__(item):
        print(f"Getting Union[{item.__name__}, MISSING]")
        return Union[item, MISSING]


lol: APINullable[str] = MISSING
lol2: APINullable[str] = "test"
lol3: APINullable[str] = 123

for i in (lol, lol2, lol3):
    print(i, type(i), i is MISSING)

代码运行输出结果如下:

Getting Union[str, MISSING]
Getting Union[str, MISSING]
Getting Union[str, MISSING]
<class '__main__.MissingType'> <class 'type'> True
test <class 'str'> False
123 <class 'int'> False

上述输出完全符合预期,但Pycharm、搭载Pylance的VSCode以及MyPy均无法识别该自定义类型,MyPy的报错信息如下:

test.py:18: error: "APINullable" expects no type arguments, but 1 given
test.py:18: error: Incompatible types in assignment (expression has type "Type[MissingType]", variable has type "APINullable")
test.py:19: error: "APINullable" expects no type arguments, but 1 given
test.py:19: error: Incompatible types in assignment (expression has type "str", variable has type "APINullable")
test.py:20: error: "APINullable" expects no type arguments, but 1 given
test.py:20: error: Incompatible types in assignment (expression has type "int", variable has type "APINullable")
Found 6 errors in 1 file (checked 1 source file)

已提交相关issue确认是否为类型系统Bug,同时希望得到可行的解决方法。

原因说明

静态类型检查器(MyPy、Pylance等)不会执行代码的运行时逻辑,因此无法感知你在__class_getitem__中返回Union类型的操作,只会将APINullable识别为普通类,自然不支持传入泛型参数,也不会匹配你预期的类型规则。

解决方案

根据你的使用场景可以选择以下两种方案:

方案1:仅需类型约束,无额外运行时逻辑

直接使用泛型类型别名,代码最简洁,完全符合PEP484规范,所有类型检查器都可以完美识别:

from typing import Union, TypeVar

T = TypeVar('T')

class MissingType(type):
    ...

MISSING = MissingType
# 直接定义泛型别名
APINullable = Union[T, MISSING]

方案2:需要保留__class_getitem__的运行时逻辑

继承Generic基类声明该类型支持泛型参数,让类型检查器可以识别你的泛型写法:

from typing import Union, Generic, TypeVar

T = TypeVar('T')

class MissingType(type):
    ...

MISSING = MissingType

# 继承Generic声明泛型支持
class APINullable(Generic[T]):
    @staticmethod
    def __class_getitem__(cls, item: type[T]) -> Union[type[T], type[MissingType]]:
        print(f"Getting Union[{item.__name__}, MISSING]")
        return Union[item, MISSING]

修改后类型检查器会正确识别APINullable[str]等价于Union[str, Type[MissingType]],lol和lol2的赋值会通过检查,lol3赋值为int会正确抛出类型错误,运行时逻辑也和你原来的代码完全一致。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.04 17:57:03