12 minutes read

ENUM is a data type in Python that allows you to define a set of related, immutable constant values to give you a more structured and maintainable codebase. It helps make your code more readable, self-documenting, and error-resistant.

Creating enumerations in python

An enumeration, or ENUM, is a special type of data structure that consists of a set of named values, also known as members or enumerators. Python does not have a built-in syntax for them. However, the standard library includes the enum module that provides support for creating sets of related constants via the enum class In Python, you can create an ENUM using the enum module.

To create an ENUM, import the Enum class from the enum module. Here's an example:

from enum import Enum

Once you've imported the Enum class, you can define your ENUM by creating a new subclass. Each member of the ENUM should be defined as a class attribute with a unique name and an assigned value. For example:

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

We've defined an ENUM called Color with three members: RED, GREEN, and BLUE. Each member is assigned a unique integer value.

You can also define an ENUM member with an auto-assigned value. In this case, the value will be an integer that starts at 1 and increments by 1 for each subsequent member:

from enum import auto, Enum

class Color(Enum):
    RED = auto()
    GREEN = auto()
    BLUE = auto()

In this example, we've defined the same Color ENUM, but we've used the auto() function to automatically assign integer values to each member.

Once you've defined your ENUM, you can access its members using dot notation:

print(Color.RED)  # Output: Color.RED

You can also access the value of an ENUM member using the .value attribute:

print(Color.RED.value)  # Output: 1

That's it! You've successfully created an ENUM in Python using the enum module.

Accessing modes

Each constant is an instance of the Enum class and can be accessed either by its value or name. Here's an example of how to define and access an ENUM:

from enum import Enum

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

In this example, we've defined an ENUM called Color with three members: RED, GREEN, and BLUE. Each member has a corresponding integer value.

Now, let's see how we can access these members by their values and names:

# Accessing enum members by value
print(Color(1))    # Color.RED
print(Color(2))    # Color.GREEN
print(Color(3))    # Color.BLUE

# Accessing enum members by name
print(Color['RED'])    # Color.RED
print(Color['GREEN'])  # Color.GREEN
print(Color['BLUE'])   # Color.BLUE

We're accessing enum members by their values in the first set of examples. We're passing the integer value of each member to the Color constructor, which returns the corresponding member.

In the second set of examples, we're accessing enum members by their names. We're using the square bracket notation to access the member with the given name.

Both methods of accessing enum members are reasonable in different situations. Accessing members by value can be useful when you have a variable containing an enum member's integer value. Accessing members by name can be useful when you want to refer to an enum member in a more readable way.

Enumerations are iterable

In Python, enumerations are iterable, meaning you can loop through their members using a for loop or perform other operations that apply to iterable objects.

from enum import Enum

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


# Loop through the enumeration members
for color in Color:
    print(f"{color.name} has value {color.value}")

# Output:
# RED has value 1
# GREEN has value 2
# BLUE has value 3

In this example, we define an enumeration called Color with three members: RED, GREEN, and BLUE. We then loop through all the enumeration members using a for loop and print the name and value of each member.

By using the name and value attributes of each enumeration member, we can get the name and integer value of the color, respectively.

This is just one example of how you can iterate through an enumeration of colors. You can use this approach to perform various operations on each color in the enumeration.

Using enumerations in if and match statements

Enumerations can be used in if and match statements like any other data type. This allows you to write more expressive code that is easier to read and understand.

from enum import Enum

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

# Check whether the color is red
color = Color.RED
if color == Color.RED:
    print("The color is red")
else:
    print("The color is not red")

# Output: The color is red

In this example, we define an enumeration called Color with three members: RED, GREEN, and BLUE. We then set the variable color to Color.RED and use an if statement to check whether color is Color.RED. If it is, we print The color is red. Otherwise, we print The color is not red.

You can also use enumerations in match statements (available from Python 3.10 onwards), which provide a more concise and expressive way of checking the values of an enumeration. Here's an example:

from enum import Enum
from typing import Tuple

class Direction(Enum):
    NORTH = "N"
    EAST = "E"
    SOUTH = "S"
    WEST = "W"

# Get the opposite direction of a given direction
def opposite_direction(direction: Direction) -> Direction:
    match direction:
        case Direction.NORTH:
            return Direction.SOUTH
        case Direction.EAST:
            return Direction.WEST
        case Direction.SOUTH:
            return Direction.NORTH
        case Direction.WEST:
            return Direction.EAST

# Test the opposite_direction function
current_direction = Direction.NORTH
opposite_direction = opposite_direction(current_direction)
print(f"The opposite direction of {current_direction} is {opposite_direction}")

# Output: The opposite direction of Direction.NORTH is Direction.SOUTH

In this example, we define an enumeration called Direction with four members: NORTH, EAST, SOUTH, and WEST. We then define a function called opposite_direction that takes a direction as input and returns its opposite direction.

Inside the function, we use a match statement to check the value of the input direction and return its opposite direction. This provides a more concise and expressive way of checking the values of an enumeration compared to using a series of if-elif statements.

Comparing enumerations

By default, ENUMs in Python allow for two comparison operations: identity and equality. This means that you can compare enum members to see if they are the same object in memory (using is and is not operators), or if they have the same value (using == and != operators).

The identity comparison of enum members is possible because each member is a single instance of its enumeration class, which makes it easy and efficient to compare members using the is and is not operators.

from enum import Enum

class Animal(Enum):
    CAT = 1
    DOG = 2
    BIRD = 3
    FISH = 4
    # Aliases:
    FELINE = 1
    CANINE = 2

# Testing the identity of enum members and aliases:
cat = Animal.CAT
feline = Animal.FELINE
dog = Animal.DOG
canine = Animal.CANINE
fish = Animal.FISH
bird = Animal.BIRD

print(cat is feline)    # True
print(dog is canine)    # True
print(cat is dog)       # False
print(fish is bird)     # False
print(feline is dog)    # False

In this example, we have an enum representing different types of animals. The members CAT, DOG, BIRD, and FISH have unique identities. We also have aliases for some of the members: FELINE is an alias for CAT, and CANINE is an alias for DOG. Since aliases are just references to existing members, they share the same identity as the members they reference. Therefore, cat is feline and dog is canine both return True. However, cat is dog, fish is bird, and feline is dog all return False since these are different members with different identities.

The equality operators == and != also work between enumeration members:

from enum import Enum

class Color(Enum):
    RED = 1
    BLUE = 2
    GREEN = 3
    YELLOW = 4

# Testing the equality of enum members:
red = Color.RED
blue = Color.BLUE
green = Color.GREEN
yellow = Color.YELLOW

print(red == Color.RED)     # True
print(green == Color.RED)   # False
print(yellow == blue)       # False
print(yellow != blue)       # True

In this example, we have an enum representing different colors. We create several members with unique identities: RED, BLUE, GREEN, and YELLOW. We then test the equality of these members using the == and != operators. We see that red == Color.RED returns True since red refers to the RED member, which has the same value and identity as the RED member of the Color enum. Similarly, yellow != blue returns True since yellow refers to the YELLOW member, which has a different value and identity than the BLUE member referred to by blue.

Since ENUM members are assigned a definite value, such as a number, string, or any other object, comparing them directly with other objects using equality operators might be tempting. The outcome of such comparisons may not be as expected since the comparison is performed based on the identity of the objects rather than their values.

from enum import Enum

class Weekday(Enum):
    MONDAY = 1
    TUESDAY = 2
    WEDNESDAY = 3
    THURSDAY = 4
    FRIDAY = 5
    SATURDAY = 6
    SUNDAY = 7

# Testing the equality of enum members with integers:
monday = Weekday.MONDAY
tuesday = Weekday.TUESDAY
wednesday = Weekday.WEDNESDAY

print(monday == 1)        # False
print(tuesday == 2)       # False
print(wednesday != 3)     # True

Even though the values assigned to the enum members are the same as the integers used for comparison in the examples, the comparisons still result in False. This is because enum members are compared based on their object identity rather than their value. Comparing an enum member to an integer is like comparing two different things with different identities. Therefore, they can never be considered equal.

Using the value attribute, you can compare two members with the same values. It will return True

Additionally, enumerations have a feature that allows membership tests using the in and not in operators.

from enum import Enum

class Season(Enum):
    SPRING = 1
    SUMMER = 2
    FALL = 3
    WINTER = 4

# Testing membership of enum members:
spring = Season.SPRING
summer = Season.SUMMER
fall = Season.FALL
winter = Season.WINTER

print(summer in Season)     # True
print(spring not in Season) # False
print(fall in Season)       # True
print(winter not in Season) # False

By default, Python's enum class allows the use of the in and not in operators that can be used to verify the presence of a particular enum member in a given enumeration.

Sorting enumerations

Python's enums do not have built-in support for comparison operators such as >, <, >=, and <=. Due to this limitation, it is not possible to directly sort enum members with the sorted() function. However, sorting enumerations by their member names and values is possible using the key argument in the sorted() function.

from enum import Enum

class Season(Enum):
    SPRING = 3
    SUMMER = 2
    FALL = 1
    WINTER = 4

print(sorted(Season, key=lambda season: season.value))
#[<Season.FALL: 1>, <Season.SUMMER: 2>, <Season.SPRING: 3>, <Season.WINTER: 4>]
print(sorted(Season, key=lambda season: season.name))
#[<Season.FALL: 1>, <Season.SPRING: 3>, <Season.SUMMER: 2>, <Season.WINTER: 4>]

In the first example, a lambda function is used to extract the .value attribute of each enumeration member, which allows the input enumeration to be sorted by its member values. Similarly, in the second example, the lambda function extracts the .name attribute of each member to sort the enumeration by its member names.

Best practices and use cases

Here are some best practices and use cases for using ENUMs in Python:

  1. Use ENUM to represent a fixed set of values: ENUM is a great way to represent a selected set of values known at compile-time. This makes your code more self-documenting and error-resistant since the set of valid values is explicitly defined.

  2. Use descriptive names for ENUM members: Use descriptive names for ENUM members to make your code more readable and self-explanatory. Avoid using abbreviations or cryptic terms that may be hard to understand later.

  3. Use ENUM for constants: Use ENUM to represent constants used throughout your code. This makes it easier to change the value of a constant in the future since you only need to change it in one place.

Conclusion

  • ENUM is a data type that allows you to define a set of named values in Python.

  • ENUM can help make your code more readable, self-documenting, and less error-prone.

  • Use ENUM to represent constants used throughout your code, making it easier to change the value of a constant in the future.

19 learners liked this piece of theory. 1 didn't like it. What about you?
Report a typo