如何解决Python自定义Enum子类“index should be a string”类型报错
实现合理性说明
Python 标准 Enum 设计时,默认将 [] 运算符绑定为按成员名称查找成员的语义,和序列按下标访问的语义完全独立,因此原生没有支持整数/切片访问的设计。你的实现本身运行逻辑没有问题,只要你的项目内部明确自定义 Enum 子类的 [] 同时支持三种入参的语义,不会造成使用者的认知混淆,这个实现就是合理的。
mypy 报错解决方案
不需要使用行级 type: ignore,可以通过给元类的 __getitem__ 增加类型重载让 mypy 正确识别入参和返回值类型,修改后的代码如下:
import enum from typing import overload, Union, TypeVar T = TypeVar('T', bound='MyEnum') class MyEnumMeta(enum.EnumMeta): @overload def __getitem__(self: type[T], index: int) -> T: ... @overload def __getitem__(self: type[T], index: slice) -> list[T]: ... @overload def __getitem__(self: type[T], index: str) -> T: ... def __getitem__(self: type[T], indexOrSlice: Union[int, slice, str]) -> Union[T, list[T]]: if isinstance(indexOrSlice, (int, slice)): return list(self)[indexOrSlice] return super().__getitem__(indexOrSlice) class MyEnum(enum.Enum, metaclass=MyEnumMeta): pass class Period(MyEnum): A = "a" B = "b" C = "c" print(Period["A"]) print(Period[1]) print(Period[:2])
加上重载注解后,mypy 可以正确匹配不同入参对应的返回类型,不会再抛出「Enum index should be a string」的错误,也不会掩盖其他合法的类型问题。
mypy 问题上报说明
mypy 目前对 Enum 下标访问的校验是硬编码的规则,确实没有考虑到开发者自定义元类重写 __getitem__ 的场景,属于边界场景的漏覆盖。如果你要上报该问题,可以到 mypy 的官方代码仓库提交 Issue,附上你的最小复现代码和预期的校验行为即可。
内容的提问来源于stack exchange,提问作者Chris Santos-Lang
相关产品推荐
相关产品推荐

