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

在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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.28 22:17:47