Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Enumeration with auto-numbering starting at 0

Is there a better way to create a long list of enumeration with auto-numbering starting at 0? The closest that I can find is:

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

However, the above approach requires knowing the total items in the enumeration beforehand.

like image 368
cash Avatar asked Dec 22 '16 20:12

cash


People also ask

Does enum always start at 0?

If the first enumerator has no initializer, the value of the corresponding constant is zero. An enumerator-definition without an initializer gives the enumerator the value obtained by increasing the value of the previous enumerator by one. So yes, if you do not specify a start value, it will default to 0.

Can python enums start 0?

Enumerate with a Different Starting Index So as you know, indices in python start at 0. This means that when you use the enumerate function, the index returned for the first item will be 0.

Are enums 0 based?

Rule description. The default value of an uninitialized enumeration, just like other value types, is zero.

How do you declare an enumeration?

To declare an enumerationWrite a declaration that includes a code access level, the Enum keyword, and a valid name, as in the following examples, each of which declares a different Enum . Define the constants in the enumeration.


5 Answers

The documentation provides a recipe for autonumbering that can easily be adapted to start from zero:

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

Then you can create it with arbitrary members:

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

Alternatively, note that the functional API can take an iterable of key-value pairs:

from itertools import count

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

itertools.count is basically an open-ended equivalent of range.


However, the docs also provide the reason for members generally starting with 1:

The reason for defaulting to 1 as the starting number and not 0 is that 0 is False in a boolean sense, but enum members all evaluate to True.

Starting from zero may lead to confusing behaviour later on.

like image 191
jonrsharpe Avatar answered Oct 17 '22 07:10

jonrsharpe


As @jonrsharpe already showed, an Enum can be created like this:

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

This will be indexed (starting) by 1.

The official documentation states, from Python 3.5:

use the start parameter to specify a different starting value

As the documentation states, you can do exactly that:

Color = Enum('Color', ['RED', 'GREEN', 'BLUE'], start=0)
like image 30
Spenhouet Avatar answered Oct 17 '22 06:10

Spenhouet


The OP clarified that their motivation is to use the enum value as an array index, which implies consecutive numbering starting from zero.

The documentation states:

The goal of the default [autonumbering] methods is to provide the next int in sequence with the last int provided, but the way it does this is an implementation detail and may change.

Hence it may be wise to define the autonumbering method explicitly, for example:

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()

This will ensure that the enum values are assigned consequtive values starting from zero:

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

> 0 1 2

Note that the value property can be omitted if the context doesn't require it, e.g.:

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

> 102

like image 40
Martin CR Avatar answered Oct 17 '22 06:10

Martin CR


If you prefer declaring a class in an old fashioned way, in Python 3.6.4 you can try something like this:

from enum import Enum, auto

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

print(list(MyEnum))

should result in:

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

If you don't set FIELD_1 to 0, then enum property values shall start from 1.

like image 34
aleksandarbos Avatar answered Oct 17 '22 07:10

aleksandarbos


Just do;

from enum import IntEnum

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

Or if you want to have a class;

class Color (IntEnum):
    def __init__(*args, **kwargs):
        start = kwargs.pop('start', None)
        if start is None:
            kwargs['start'] = 0
        super().__init__(*args, **kwargs)
like image 1
Vinzent Avatar answered Oct 17 '22 06:10

Vinzent