python-3.x 从0开始自动编号的枚举

6l7fqoea  于 2022-11-19  发布在  Python
关注(0)|答案(7)|浏览(197)

有没有更好的方法来创建一个从0开始自动编号的长枚举列表?我能找到的最接近的方法是:

class Color(Enum):
    red, green, blue=range(3)

然而,上述方法需要预先知道枚举中的总项目。

bhmjp9jg

bhmjp9jg1#

该文档提供了一种自动编号方法,可以轻松地调整为从零开始:

class AutoNumber(Enum):
     def __new__(cls):
        value = len(cls.__members__)  # note no + 1
        obj = object.__new__(cls)
        obj._value_ = value
        return obj

然后,您可以使用任意成员创建它:

class Color(AutoNumber):
    red = ()
    green = ()
    blue = ()

或者,请注意,函数API可以接受可迭代的键值对:

from itertools import count

Color = Enum('Color', zip(['red', 'green', 'blue'], count()))

itertools.count基本上是range的开放式等价物。
但是,文档还提供了成员通常以1开头的原因:
默认使用1而不是0作为起始编号的原因是,0在布尔意义上是False,但枚举成员都计算为True
从零开始可能会导致稍后的混乱行为。

5uzkadbs

5uzkadbs2#

正如@jonrsharpe已经展示的,可以像这样创建枚举:

Color = Enum('Color', ['RED', 'GREEN', 'BLUE'])

这将从1开始索引。
Python 3.5中的official documentation声明:
使用start参数指定不同的起始值
如文档所述,您完全可以做到这一点:

Color = Enum('Color', ['RED', 'GREEN', 'BLUE'], start=0)
w46czmvw

w46czmvw3#

OP澄清了他们的动机是使用枚举值作为数组索引,这意味着从零开始连续编号。
documentation声明:
default [autonumbering]方法的目标是提供序列中的下一个int,而不是提供的最后一个int,但是它执行此操作的方式是实现细节,可能会改变
因此,明确定义自动编号方法可能是明智的,例如:

from enum import IntEnum, auto
class PrimaryColours(IntEnum):
    def _generate_next_value_(name, start, count, last_values):
        """generate consecutive automatic numbers starting from zero"""
        return count

    RED = auto()
    GREEN = auto()
    BLUE = auto()

这将确保为enum值分配从零开始的连续值:

print(PrimaryColours.RED.value,
      PrimaryColours.GREEN.value,
      PrimaryColours.BLUE.value)

一个月一个月

请注意,如果上下文不需要value属性,则可以省略该属性,* 例如 *:

orange = (255, 102, 0)
print(orange[PrimaryColours.GREEN])

> 102

nkoocmlb

nkoocmlb4#

如果你更喜欢用传统的方法声明一个类,在Python 3.6.4中,你可以尝试这样的方法:

from enum import Enum, auto

class MyEnum(Enum):
    FIELD_1 = 0
    FIELD_2 = auto()
    FIELD_3 = auto()

print(list(MyEnum))

应导致:

>> [<MyEnum.FIELD_1: 0>, <MyEnum.FIELD_2: 1>, <MyEnum.FIELD_3: 2>]

如果未将FIELD_1设置为0,则枚举属性值应从1开始。

bihw5rsg

bihw5rsg5#

"做吧"

from enum import IntEnum

color = IntEnum('color', ['red', 'green', 'blue'], start=0)

或者如果你想上课;

class Color (IntEnum):
    def __init__(*args, **kwargs):
        start = kwargs.pop('start', None)
        if start is None:
            kwargs['start'] = 0
        super().__init__(*args, **kwargs)
cig3rfwq

cig3rfwq6#

我遇到了这个问题和答案,因为我正在寻找一种方法来设置一个IntEnum的起始值与自动编号。我找到了我的问题的答案放在一起的零碎的答案在这里。
我补充我的答案,也是因为我认为有一个一般性的解决办法可能是有用的。

from enum import IntEnum, auto, unique

class MyEnum(IntEnum):
    
    def _generate_next_value_(name, start, count, last_values):
        # name is the item name
        #
        # start is the automatic numbering starting value and 
        # it is exactly what you want to change. Default = 1
        # Set start to whatever number
        # you want. 0 in the case of the current question.
        
        start=0
        
        #
        # count is the number of items in the enumerator so far
        # 
        # last_values is a list of used values so far.

        return IntEnum._generate_next_value_(name, start, count, last_values)
                
    A = auto()
    B = auto()
    F = auto()
    C = auto()
    D = auto()
    
for e in MyEnum:
    print(f'{e=}')

这个想法很简单,IntEnum的枚举器子类重载基类 generate_next_value 方法,设置一个不同的起始值。非常简单,非常优雅,适用于所有可能的起始值。

y1aodyip

y1aodyip7#

另一个替代方案,我基于emums.py

from enum import IntEnum

class IntEnumZero(IntEnum):
    # Taken from enums.py
    def _generate_next_value_(name, start, count, last_values):
        for last_value in reversed(last_values):
            try:
                return last_value + 1
            except TypeError:
                pass
        else:
            return 0 #<---CHANGED to 0 instead of <start>

class UsbError(IntEnumZero):
    ZERO = auto() # 0
    ONE = auto() # 1

相关问题