Python Enum aliases & @enum.unique Decorator

Created with Sketch.

Python Enum aliases & @enum.unique Decorator

 

Summary: in this tutorial, you’ll learn about enumeration member aliases and how to use the enum unique decorator to ensure the uniqueness of member values.

Introduction to the enum aliases

By definition, the enumeration member values are unique. However, you can create different member names with the same values.

For example, the following defines the Color enumeration:

from enum import Enum

class Color(Enum):
RED = 1
CRIMSON = 1
SALMON = 1
GREEN = 2
BLUE = 3

Code language: Python (python)

In this example, the Color enumeration has the RED, CRIMSON, and SALMON members with the same value 1.

When you define multiple members in an enumeration with the same values, Python does not create different members but aliases.

In this example, the RED is the main member while the CRIMSON and SALMON members are the aliases of the RED member

The following statements return True because CRIMSON and SALMON members are RED meber:

print(Color.RED is Color.CRIMSON)
print(Color.RED is Color.SALMON)

Code language: Python (python)

Output:

True
True

Code language: Python (python)

When you look up a member by value, you’ll always get the main member, not aliases. For example, the following statement returns the RED member:

print(Color(1))

Code language: Python (python)

Output:

Color.RED

Code language: Python (python)

When you iterate the members of an enumeration with aliases, you’ll get only the main members, not the aliases. For example:

for color in Color:
print(color)

Code language: Python (python)

It returns only three members:

Color.RED
Color.GREEN
Color.BLUE

Code language: Python (python)

To get all the members including aliases, you need to use the __member__ property of the enumeration class. For example:

from enum import Enum
from pprint import pprint

class Color(Enum):
RED = 1
CRIMSON = 1
SALMON = 1
GREEN = 2
BLUE = 3

pprint(Color.__members__)

Code language: Python (python)

Output:

mappingproxy({'BLUE': <Color.BLUE: 3>,
'CRIMSON': <Color.RED: 1>,
'GREEN': <Color.GREEN: 2>,
'RED': <Color.RED: 1>,
'SALMON': <Color.RED: 1>})

Code language: Python (python)

As shown clearly from the output, the CRIMSON and SALMON reference the same object which is referenced by the RED member:

<Color.RED: 1>

Code language: Python (python)

When to use enum aliases

Enumeration aliases can be helpful in some situations. For example, suppose that you have to deal with API from two different systems. And each system has a different response status doe with the same meaning as shown in the following table:

System 1System 2Meaning
REQUESTINGPENDINGThe request is in progress
OKFULFILLEDThe request was completed successfully
NOT_OKREJECTEDThe request was failed

To standardize the status codes from these systems, you can use enumeration aliases as follows:

Your SystemSystem 1System 2Meaning
IN_PROGRESSREQUESTINGPENDINGThe request is in progress
SUCCESSOKFULFILLEDThe request was completed successfully
ERRORNOT_OKREJECTEDThe request was failed

The following defines the ResponseStatus enumeration with aliases:

from enum import Enum

class ResponseStatus(Enum):
# in progress
IN_PROGRESS = 1
REQUESTING = 1
PENDING = 1

# success
SUCCESS = 2
OK = 2
FULFILLED = 2

# error
ERROR = 3
NOT_OK = 3
REJECTED = 3

Code language: Python (python)

The following compares the response code from system 1 to check if the request was successful or not:

code = 'OK'
if ResponseStatus is ResponseStatus.SUCCESS:
print('The request completed successfully')

Code language: Python (python)

Output:

The request completed successfully

Code language: Python (python)

Likewise, you can check the response code from system 2 to see if the request was successful:

code = 'FULFILLED'
if ResponseStatus is ResponseStatus.SUCCESS:
print('The request completed successfully')

Code language: Python (python)

Output:

print('The request completed successfully')

Code language: Python (python)

@enum.unique decorator

To define an enumeration with no aliases, you can carefully use unique values for the members. For example:

from enum import Enum

class Day(Enum):
MON = 'Monday'
TUE = 'Tuesday'
WED = 'Wednesday'
THU = 'Thursday'
FRI = 'Friday'
SAT = 'Saturday'
SUN = 'Sunday'

Code language: Python (python)

But you can accidentally use the same values for two members like this:

class Day(Enum):
MON = 'Monday'
TUE = 'Monday'
WED = 'Wednesday'
THU = 'Thursday'
FRI = 'Friday'
SAT = 'Saturday'
SUN = 'Sunday'

Code language: Python (python)

In this example, the TUE member is the alias of the MON member, which you may not expect.

To ensure an enumeration has no alias, you can use the @enum.unique decorator from the enum module.

When you decorate an enumeration with the @enum.unique decorator, Python will throw an exception if the enumeration has aliases.

For example, the following will raise a ValueError:

import enum

from enum import Enum

@enum.unique
class Day(Enum):
MON = 'Monday'
TUE = 'Monday'
WED = 'Wednesday'
THU = 'Thursday'
FRI = 'Friday'
SAT = 'Saturday'
SUN = 'Sunday'

Code language: Python (python)

Error:

ValueError: duplicate values found in <enum 'Day'>: TUE -> MON

Code language: Python (python)

Summary

  • When an enumeration has different members with the same values, the first member is the main member while others are aliases of the main member.
  • Use the @enum.unique decorator from the enum module to enforce the uniqueness of the values of the members.

Leave a Reply

Your email address will not be published. Required fields are marked *