具有 infinite/dynamic 个成员的枚举

Enum with infinite/dynamic members

摘要:我想要一个(整数)枚举,它有一些对应于特定状态的(负)成员和未绑定(正)成员。

示例:假设我们有一个数据库条目,用于存储比赛中的获胜位置。如果比赛结束,这些条目是积极的。但是,也有一些特殊值,例如没有参加没有参加取消资格。这些作为负值存储在数据库中。

现在我想在Python中表示这个结构。由于枚举是不可变的,因此这变得相当困难。我已经研究了 enum.EnumMeta 并查看了 aenum 库,但没有找到解决方案。我最不荒谬的想法是有一个像下面这样的枚举:

import enum

class RankingPlace(enum.IntEnum):
    FINISHED = 0
    DID_NOT_FINISH = -1
    DID_NOT_ATTEND = -2
    DISQUALIFIED = -3

    def __call__(self, value):
        if value < 0:
            return super()(member)
        else:
            member = self.__class__.FINISHED
            member.actual_place = value
            return member

这有点管用,但我必须打电话给会员才能让它发挥作用。是否有更清洁的方式使用例如自定义元类?

听起来最好的解决方案是 Enum 和其他东西的组合——也许是 namedtuple(使用 aenum 中的 NamedTuple 的示例代码:

class Status(aenum.IntEnum):
    FINISHED = 0
    DID_NOT_FINISH = -1
    DID_NOT_ATTEND = -2
    DISQUALIFIED = -3

class Placement(aenum.NamedTuple):
    race = 0, 'name of race'
    status = 1, 'finished race?'
    placement = 2, 'position when finished'

winner = Placement('2021 Marathon', Status.FINISHED, 1)

我已经考虑过元组,但想将所有内容都保存在一个 class 中,因为我必须对多个枚举执行此操作,并且不喜欢每个枚举都有两个 class。这部分是由于我们在应用程序中使用运行时验证机制并试图保持代码干燥。

但是阅读@Ethan 的回答和上面的评论我想出了一个聪明的解决方案(或者我认为)它仍然允许 mypy 正确检查类型。

from enum import IntEnum
from typing import Generic, TypeVar

E = TypeVar("E", bound=IntEnum)

# use Generic as mypy does not support generic NamedTuple yet
class InfiniteEnum(Generic[E]):
    def __init__(self, enum: E, int_: int):
        self.enum = enum
        self.int = int_

class Status(IntEnum):
    FINISHED = 0
    DID_NOT_FINISH = -1
    DID_NOT_ATTEND = -2
    DISQUALIFIED = -3

winner = InfiniteEnum[Status](Status.FINISHED, 1)

如果只需要一次,我接受的答案可能更清晰。