如何实现含可变成员、可按seq_id比较及哈希的Python Enum
实现满足特定需求的工业流程阶段枚举类
我正在编写一个类来表示工业流程的连续阶段,包含ADMISSION、PROCESSING、QC和DELIVERY这几个阶段。每个阶段拥有唯一的递增序列号seq_id、助记名称name,以及记录流经该阶段实例数量的字段n_instances:
@dataclass class Stage: seq_id: int name: str n_instances: int
由于这些阶段是固定的,执行期间不会变更,我决定将它们整合到一个Enum中。该Enum需要满足以下要求:
枚举成员需:
- 作为Stage的子类,无需访问value即可使用(类似IntEnum或StrEnum),具体要求:
- 可通过seq_id进行比较(例如
Stages.DELIVERY > Stages.PROCESSING应为真) - 可作为字典的键
- 使用name作为
__str__的返回值
- 可通过seq_id进行比较(例如
- 具备基于声明顺序生成的、从0到n的不可变连续seq_id
- 在成员声明时指定name,使用
auto()时生成小写的成员名称
我已在实现中完成了第2和第3点,请问如何实现第1点及其子需求?
最终实现(感谢@EthanFurman的解答)
核心思路
- 将Stage实例作为枚举成员,把seq_id直接存储在枚举成员的
_value_中(seq_id仅在枚举内部有意义) - seq_id基于声明顺序自动生成(借助自动编号枚举模式),避免手动指定带来的无效值问题
- 比较、哈希、字符串转换等方法在枚举类中实现,而非Stage类,因为这些行为与枚举成员的使用强绑定
- 哈希基于枚举成员的
_value_(不可变),避免因Stage实例的可变性导致哈希异常
from dataclasses import dataclass from enum import Enum, auto from functools import total_ordering from typing import override @dataclass class Stage: label: str n_instances: int = 0 @total_ordering class Stages(Stage, Enum): # 满足需求1:成员为Stage的子类 # 需求1.1:基于seq_id比较 def __lt__(self, other): if self.__class__ is other.__class__: return self.value < other.value return NotImplemented def __eq__(self, other): if self.__class__ is other.__class__: return self.value == other.value return NotImplemented # 需求1.2:可作为字典键 def __hash__(self): return hash(self.value) # 需求1.3:__str__返回name def __str__(self): return self.label # 需求2:自动生成连续seq_id def __new__(cls, label): # 自动编号生成seq_id value = len(cls.__members__) + 1 obj = Stage.__new__(cls) # 将seq_id设为枚举成员的value obj._value_ = value return obj # 需求3:auto()生成小写成员名称 @override def _generate_next_value_(name, start, count, last_values): return name.lower() ADMISSION = auto() PROCESSING = auto() QC = auto() DELIVERY = auto() # 排序测试 assert Stages.PROCESSING < Stages.DELIVERY # 字典键测试 stage_to_color = { Stages.ADMISSION : "#B10156", Stages.PROCESSING : "#F4B704", Stages.QC : "#FD0002", Stages.DELIVERY : "#7FB857" } assert stage_to_color[Stages.QC] == "#FD0002"
内容的提问来源于stack exchange,提问作者Afelium
相关产品推荐
相关产品推荐

