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

如何用类Enum的结构生成类型而非值?兼容类型提示与泛型

实现兼容泛型与类型提示的元枚举结构

你需要的是一种元枚举——既保留Enum的简洁定义、字符串关联、反向查找等特性,又让每个成员本身是可用于泛型的类型。以下是符合所有需求的最优实现:

完整代码实现

from typing import Generic, TypeVar, Type

# 所有维度类型的基类,用于泛型约束
class DimensionBase:
    symbol: str

# 自定义元类,复刻Enum核心特性并生成类型成员
class DimensionMeta(type):
    _symbol_to_type: dict[str, Type[DimensionBase]] = {}
    _name_to_type: dict[str, Type[DimensionBase]] = {}

    def __new__(cls, name, bases, namespace, symbol=None):
        # 创建维度类型
        dim_cls = super().__new__(cls, name, bases, namespace)
        if symbol is not None:
            # 为有效维度类型绑定symbol,并注册到映射表
            dim_cls.symbol = symbol
            cls._symbol_to_type[symbol] = dim_cls
            cls._name_to_type[name] = dim_cls
            # 将维度类型挂载到元类实例(即Dim类)上,模拟Enum的Dim.TIME调用
            setattr(cls, name, dim_cls)
        return dim_cls

    def __call__(cls, symbol: str) -> Type[DimensionBase]:
        # 实现Enum的反向查找:Dim('t') -> TIME类型
        if symbol in cls._symbol_to_type:
            return cls._symbol_to_type[symbol]
        raise ValueError(f"Unknown dimension symbol: '{symbol}'")

# 维度容器类,使用自定义元类
class Dim(metaclass=DimensionMeta):
    pass

# 定义具体维度,语法简洁度接近Enum
class TIME(Dim, symbol="t"):
    pass

class MASS(Dim, symbol="m"):
    pass

# 测试泛型与类型提示
T = TypeVar("T", bound=DimensionBase)

class PhysicalQuantity(Generic[T]):
    def __init__(self, value: float):
        self.value = value

class Container:
    some_time: PhysicalQuantity[TIME]  # 类型提示完全生效,符合直觉
    some_mass: PhysicalQuantity[MASS]

# 验证Enum特性
print(Dim.TIME)          # <class '__main__.TIME'>
print(Dim('t'))          # <class '__main__.TIME'>
print(TIME.symbol)       # 't'

方案优势说明

  1. 定义简洁:只需继承Dim并指定symbol参数,和Enum的TIME = "t"写法几乎一致,无需额外冗余代码。
  2. 类型系统完全兼容:TIME/MASS是DimensionBase的子类,可直接作为泛型参数使用,类型检查器(如mypy)能正常识别PhysicalQuantity[TIME]的约束。
  3. 完整复刻Enum核心特性:
    • 通过Dim.TIME直接访问维度类型;
    • 通过Dim('t')实现反向查找;
    • 每个维度类型自带symbol属性,轻松关联字符串值。
  4. 逻辑清晰:所有维度类型统一在Dim命名空间下,结构和Enum完全一致,符合开发者使用习惯。

对比现有方案的改进

  • 比Literal方案更直观:无需每次写Literal[Dim.TIME],直接用维度类型作为泛型参数,符合用户对Dim.TIME作为类型的直觉预期。
  • 比单纯类继承方案更贴近Enum行为:Dim作为元类,实现了Dim.TIME的调用方式,而非分散的独立类。
  • 比普通元类方案更完整:新增了Enum的反向查找特性,保留了Enum的所有核心使用体验。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.16 13:13:09