有没有办法强制执行枚举允许拥有的成员数量?

问题描述 投票:0回答:1

如果我自己定义了它,那么创建一个具有恰好 n 个成员的枚举是微不足道的:

class Compass(enum.Enum):
    NORTH = enum.auto()
    EAST = enum.auto()
    SOUTH = enum.auto()
    WEST = enum.auto()

## or ##

Coin = enum.Enum('Coin', 'HEADS TAILS')

但是如果这个枚举将被发布到野外并被其他用户子类化怎么办?让我们假设它的一些额外行为取决于拥有正确数量的成员,因此我们需要强制用户正确定义它们。

这是我想要的行为:

class Threenum(enum.Enum):
    """An enum with exactly 3 members, a 'Holy Enum of Antioch' if you will.

    First shalt thou inherit from it. Then shalt though define members three,
    no more, no less. Three shall be the number thou shalt define, and the
    number of the members shall be three. Four shalt thou not define, neither
    define thou two, excepting that thou then proceed to three. Five is right
    out. Once member three, being the third member, be defined, then employest
    thou thy Threenum of Antioch towards thy problem, which, being intractible
    in My sight, shall be solved.
    """
    ...

class Triumvirate(Threenum):  # success
    CEASAR = enum.auto()
    POMPEY = enum.auto()
    CRASSUS = enum.auto()

class TeenageMutantNinjaTurtles(Threenum):  # TypeError
    LEONARDO = 'blue'
    DONATELLO = 'purple'
    RAPHAEL = 'red'
    MICHELANGELO = 'orange'

Trinity = Threenum('Trinity', 'FATHER SON SPIRIT')  # success

YinYang = Threenum('Schwartz', 'UPSIDE DOWNSIDE')  # TypeError

覆盖

_generate_next_value_()
允许强制执行最大数量的成员,但不是最小数量。

python enums
1个回答
0
投票

这是元类的工作。

enum
模块提供了一个元类,您可以用您想要的行为来扩展它。最简单的方法是在元类中定义 n

class ThreenumMeta(enum.EnumMeta):
    """Meta class for making enums with exactly 3 members."""
    n = 3

    def __new__(meta, *args, **kwargs):
        cls = super().__new__(meta, *args, **kwargs)
        if len(cls) not in [0, meta.n]:
            raise TypeError(f'{cls} must have exactly {meta.n} members.')
        return cls


class Threenum(enum.Enum, metaclass=ThreenumMeta):
    """An enum with exactly 3 members."""
    ...

这样做,您最终会为每个 n 成员枚举获得一个元类。如果您需要使用多个 n 值来执行此操作,或者如果 n 未知且需要动态,那么您需要更灵活的元类,它允许您指定 n 的值。

class EnumMeta_NMany(enum.EnumMeta):
    """Meta class for making enums with exactly n many members. n specifed by kwarg."""

    def __new__(meta, name, bases, classdict, n=None):
        cls = super().__new__(meta, name, bases, classdict)
        cls.n = getattr(cls, 'n', None) or n
        if cls.n is None:
            raise TypeError(f'{cls} must specify required number of members with `n` kwarg.')
        if len(cls) not in [0, cls.n]:
            raise TypeError(f'{cls} must have exactly {cls.n} members.')
        return cls

class TwoEnum(enum.Enum, metaclass=EnumMeta_NMany, n=2):
    """An enum with exactly 2 members."""
    ...

class Threenum(enum.Enum, metaclass=EnumMeta_NMany, n=3):
    """An enum with exactly 3 members."""
    ...
© www.soinside.com 2019 - 2024. All rights reserved.