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
相关产品推荐
相关产品推荐

