在Enum类中使用简单描述符实现类常量时mypy类型识别异常的问题咨询
问题分析与解决办法
这不是你的实现问题,而是mypy对Enum类型的特殊处理逻辑导致的。
Enum类背后的EnumMeta元类会把类里的大部分属性包装成枚举成员,而mypy的类型推断系统默认会把Enum类中的属性当成枚举实例(也就是你看到的Literal[my_module.B.y]?这种类型)——哪怕这个属性是描述符,它也会优先遵循Enum成员的类型规则,而不是应用描述符__get__方法的返回类型。
解决办法
方法一:用类级@property替代自定义描述符
如果你的需求只是实现一个返回固定值的类常量,@classmethod + @property的组合可以让mypy正确识别类型,同时达到类似描述符的效果:
from enum import Enum class B(Enum): One = 1 Two = 2 @classmethod @property def y(cls) -> int: return 10 reveal_type(B.y) # mypy会识别为"builtins.int"
这个方案简单直接,不需要自定义描述符,mypy能完美推断返回类型。
方法二:显式标注类型+typing.cast(适合必须用自定义描述符的场景)
如果你必须保留自定义描述符,可以显式标注属性类型,并在访问时用cast告诉mypy正确的类型:
from enum import Enum from typing import cast, TypeVar T = TypeVar('T') class ConstantDescriptor: def __init__(self, value: T) -> None: self.value = value def __get__(self, obj: object, objtype: type | None = None) -> T: return self.value class B(Enum): One = 1 Two = 2 y: int = ConstantDescriptor(10) # 显式标注属性类型 # 访问时用cast明确类型 reveal_type(cast(int, B.y)) # mypy会识别为"builtins.int"
不过这种方法需要每次访问都添加cast,略显繁琐,但能解决类型推断问题。
方法三:修改mypy配置(不推荐)
你可以在mypy配置文件中添加:
[mypy] strict_enum = False
这会让mypy对Enum的类型推断更宽松,但可能破坏其他Enum相关的类型检查,所以除非你明确知道后果,否则不推荐使用。
关于是否是Bug的说明
这更像是mypy的设计选择:Enum的核心用途是定义枚举成员,mypy默认假设类内属性都是枚举项,因此对描述符的支持有限。你可以去mypy的GitHub仓库搜索相关issue,不少开发者都提过类似需求,后续版本可能会优化这个场景的类型推断。
内容的提问来源于stack exchange,提问作者bad_coder
相关产品推荐
相关产品推荐

