Enums

Indices and tables

Definition

An enumeration is a set of names bound to unique, constant values. It associates friendly string names to constants.

Python doesn’t have a native enumeration type as part of the standard type hierarchy. Prior to Python 3.4 you could use namedtuple() to work around this. However Python 3.4 introduced the enum module (based on PEP 435) which is a cleaner way to create enums.

Tip

The namedtuple() class has not been deprecated. It is a class for creating 1 or more objects that contain data accessible by name. An enumeration is a single object that associated a name with a constant value. It happened to be used in the past to mimic an enumeration but that does not mean it is now obsolete.

Two classes are now available for creating enumerations; Enum and IntEnum.

Enum

MUTABILITY: Immutable

Enums can be created in two ways, both of which create a new class in the namespace:

  • Using class based syntax, where you derive from Enum, and then add members with the names and values you want to associate with the enum. For example:

    >>> from enum import Enum
    >>> class Season(Enum):
    ...     winter = 1
    ...     spring = 2
    ...     summer = 3
    ...     fall   = 4
    
    >>> dir(Season)
    ['__class__',
    '__doc__',
    '__members__',
    '__module__',
    'fall',
    'spring',
    'summer',
    'winter']
    
  • Using functional syntax, where you call the Enum constructor using the following general syntax:

    Enum(name, field_iterable)

    Where name is the name to give the enumeration. field_iterable is a source of the enumeration member names and can be one of the following:

    • A whitespace-separated string of names, as in:

      >>> from enum import Enum
      >>> Seasons = Enum('Seasons', 'winter spring summer fall')
      
    • A list of names, as in:

      >>> from enum import Enum
      >>> Seasons = Enum('Seasons', ['winter',
      ...                            'spring',
      ...                            'summer',
      ...                            'fall'])
      
    • A list of 2-tuples with key/value pairs, as in:

      >>> from enum import Enum
      >>> Seasons = Enum('Seasons', [('winter', 1),
      ...                            ('spring', 2),
      ...                            ('summer', 3),
      ...                            ('fall',   4)])
      
    • A mapping of names to values, as in:

      >>> from enum import Enum
      >>> Seasons = Enum('Seasons', {'winter': 1,
      ...                            'spring': 2,
      ...                            'summer': 3,
      ...                            'fall':   4})
      

Tip

The examples show enum member values sequentially from 1-4, but, this is not required. You can use any numbers and they need not be sequential. In fact, you don’t even need to use numbers as enum values can be any Python type! For example:

>>> from enum import Enum
>>> class Color(Enum):
...   red = (255, 0, 0)
...   green = (0, 255, 0)
...   blue  = (0, 0, 255)
>>> Color.red.value
(255, 0, 0)

Warning

You can’t have 2 enum members with the same name but you can have 2 enum members with the same value (the subsequent members alias’ the first).

In the above example, the enumeration is called “Season”.

The enumeration has the following 4 members:

  • Season.winter
  • Season.spring
  • Season.summer
  • Season.fall

The enumeration names are:

  • winter
  • spring
  • summer
  • fall

And the enumeration values are:

  • 1
  • 2
  • 3
  • 4

Each enumeration member is the type name of the enumeration:

>>> type(Season.winter)
<enum 'Season'>

Enum members print naturally:

>>> print(Season.winter)
Season.winter

You can also print the member names and values using pre-defined attributes name and value:

>>> print(Season.winter.name)
winter
>>> print(Season.winter.value)
1

You can iterate over enumeration members:

>>> for season in Seasons:
>>>     print(season)
Seasons.summer
Seasons.fall
Seasons.spring
Seasons.winter

It is possible to access enumeration members by definition order using the callable-class syntax:

>>> Season(1)
<Season.winter: 1>

It is also possible to access enumeration members by name using the item access operator []:

>>> Season['winter']
<Season.winter: 1>

The immutability of Enums means they are hashable and thus they can be used as keys in dictionaries and elements of sets. For example:

>>> favorite_sports = {}
>>> favorite_sports[Seasons.winter] = 'hockey'
>>> favorite_sports[Seasons.spring] = 'curling'
>>> favorite_sports[Seasons.summer] = 'baseball'
>>> favorite_sports[Seasons.fall] =   'football'
>>> favorite_sports
{<Seasons.fall: 4>: 'football',
 <Seasons.spring: 2>: 'curling',
 <Seasons.summer: 3>: 'baseball',
 <Seasons.winter: 1>: 'hockey'}

Enum members support comparison. The preferred method is by identity using the is operator as it is the fastest:

>>> Season.winter is Season.winter
True
>>> Season.winter is Season.fall
False

Although, the == and != operators are supported:

>>> Season.winter == Season.winter
True
>>> Season.winter == Season.fall
False

The operators, <, <=, > and >= are not supported by enum members and their use will throw a TypeError.

The Enum class does not support direct comparison to integers and will always return False. For example, the following should intuitively be true, but returns false:

>>> Season.winter == 1
False

If you need to do comparisons to straight integers, use IntEnum instead.

IntEnum

MUTABILITY: Immutable

The same as Enum except it allows comparison to integers and not just to enum members. For example:

>>> from enum import IntEnum
>>> class Season(IntEnum):
...     winter = 1
...     spring = 2
...     summer = 3
...     fall   = 4
>>> Season.winter == 1
True

Keep in mind that comparing a IntEnum to a Enum still returns False, always.

Tip

Avoid the use of IntEnum if you can. The reason being, due to the fact that you can compare to integers, that therefore allows you to compare to other unrelated enumerations, which can lead to unintentional errors. For example, although the following makes semantic sense, it is logically incorrect to compare these two classes together as they represent different types of information:

>>> from enum import IntEnum
>>> class Season(IntEnum):
...     winter = 1
...     spring = 2
...     summer = 3
...     fall   = 4
>>> class FluSeverity(IntEnum):
...     severe   = 1
...     moderate = 2
...     low      = 3
...     mild     = 4
>>> Season.winter == FluSeverity.severe
True

Try it!

Try the following:

  • Create an Enum class that assigns a value to the days of the week.

  • Return the value of the day, ‘Friday’.

  • Create an Enum class that assigns a value to the following terms:

    • “Never”
    • “Sometimes”
    • “Always”
  • Using the 2 Enums created above, create a dictionary which maps the days of the week to whether we have to come to work.