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 = 3Code language: Python (python)

In this example, the Color enumeration has the REDCRIMSON, 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 TrueCode 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.REDCode 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.BLUECode 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 = 3Code 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[code] is ResponseStatus.SUCCESS: print('The request completed successfully')Code language: Python (python)

Output:

The request completed successfullyCode language: Python (python)

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

code = 'FULFILLED' if ResponseStatus[code] 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

Comments

Leave a Reply

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