Understanding Enums in Python

Understanding Enums in Python

Enumerations, or enums, in Python are a versatile feature that allows you to define symbolic names bound to unique, constant values. Whether you're working with simple enums or advanced features like Flag and StrEnum, understanding how to utilize enums can make your code more meaningful and maintainable.
Cemil Tokatli
June 11, 2025
Topics:
Share:

Enums in Python allow you to create a set of symbolic names for unique values. This feature, introduced in Python 3.4, can make your code cleaner and less error-prone by replacing common integers or strings with meaningful names. In this guide, we will explore basic enums, the Flag class for bitwise operations, and the StrEnum for string-based enums.

Basic Enum Usage

In Python, the Enum class is used to define enumerations. Let's start by creating a basic enum.

from enum import Enum

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

# Accessing enum members
print(Color.RED)  # Output: Color.RED

Enum members in Python have two fundamental attributes that provide essential information about them:

  • name: This attribute contains the string name of the enum member, reflecting the identifier used in the enum class definition.
  • value: This attribute holds the actual value associated with the enum member, which can be any data type, commonly integers or strings.

These attributes allow you to clearly access and understand each enum member's identity and its corresponding value, aiding in debugging and code clarity.

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

Iterating Over Enums

You can iterate over the members of an enum.

for color in Color:
    print(color)
# Output:
# Color.RED
# Color.GREEN
# Color.BLUE

Comparison of Enum Members

Enum members are unique within the same enumeration and can be compared using equality operators. Identity checks, using is, ensure that they are identical instances in the context of their enum.

current_color = Color.RED
if current_color == Color.RED:
    print("The color is Red.")  # Output: The color is Red

if current_color is Color.RED:
    print("Confirmed: The color instance is Red.")  # Output: Confirmed: The color instance is Red

Advanced Enum Features

Auto Value Assignment

The auto() function assigns increasing integer values automatically to enum members.

from enum import Enum, auto

class State(Enum):
    START = auto()
    RUNNING = auto()
    FINISHED = auto()

print(State.START.value)   # Output: 1

Enum Methods and Attributes

Enums provide several useful properties and attributes, such as name and value, and access to the __members__ attribute that contains all enum members.

print(list(Color.__members__.items()))
# Output: [('RED', <Color.RED: 1>), ('GREEN', <Color.GREEN: 2>), ('BLUE', <Color.BLUE: 3>)]

Using Flag for Bitwise Operations

The Flag class in the enum module enables the creation of enums suitable for bitwise operations. This is ideal for scenarios where multiple flags or options need to be combined and checked efficiently.

Flag allows you to perform bitwise operations with enum members, such as combining them using | (OR) and checking membership with in.

from enum import Flag, auto

class Permission(Flag):
    READ = auto()
    WRITE = auto()
    EXECUTE = auto()

user_perm = Permission.READ | Permission.WRITE

if Permission.READ in user_perm:
    print("User has read permission.")

In this example, user_perm can have multiple permissions, demonstrating how Flag handles option combinations.

Consider a more complex scenario where you define various roles and permissions for a user access control system. Each role may have a unique combination of permissions.

from enum import Flag, auto

class Role(Flag):
    USER = auto()
    MODERATOR = auto()
    ADMIN = auto()

class Access(Flag):
    READ = 1
    WRITE = 2
    DELETE = 4
    BAN = 8

# Define roles with specific permissions
role_permissions = {
    Role.USER: Access.READ,
    Role.MODERATOR: Access.READ | Access.WRITE,
    Role.ADMIN: Access.READ | Access.WRITE | Access.DELETE | Access.BAN,
}

def check_permissions(role: Role, access: Access):
    if access in role_permissions[role]:
        return f"Role '{role.name}' has '{access.name}' permission."
    else:
        return f"Role '{role.name}' does not have '{access.name}' permission."

# Example usage
print(check_permissions(Role.USER, Access.READ))       # Output: Role 'USER' has 'READ' permission.
print(check_permissions(Role.MODERATOR, Access.DELETE))  # Output: Role 'MODERATOR' does not have 'DELETE' permission.
print(check_permissions(Role.ADMIN, Access.BAN))       # Output: Role 'ADMIN' has 'BAN' permission.

Combining multiple permissions using the | operator and verifying specific access rights with the in operator is a crucial feature of Flag. This enhances flexibility when managing complex permission sets efficiently.

# Combining multiple permissions into a single set
combined_perm = Access.READ | Access.WRITE | Access.DELETE
print(combined_perm)  # Output: Access.READ|WRITE|DELETE

# Checking if specific permissions are enabled within the combined set
print(Access.WRITE in combined_perm)  # Output: True
print(Access.BAN in combined_perm)    # Output: False

# Understanding the behavior of the 'in' operator
if Access.READ in combined_perm:
    print("Read access is included.")  # Output: Read access is included.

if Access.BAN in combined_perm:
    print("Ban access is included.")   # This will not execute
else:
    print("Ban access is not included.")  # Output: Ban access is not included.

By leveraging Flag and bitwise operations, you can effectively manage complex permission systems, maintaining both clarity and flexibility in access control. This reinforces how Flag contributes to more intuitive and robust program design in Python.

StrEnum for String-Based Enums

As of Python 3.11, StrEnum is used for enums where each member's value is the same as its name, automatically converting enum members to strings.

from enum import StrEnum, auto

class Status(StrEnum):
    IN_PROGRESS = auto()
    COMPLETED = auto()

current_status = Status.IN_PROGRESS
if current_status == Status.IN_PROGRESS:
    print("The status is In Progress.")  # Output: The status is In Progress

Enums in StrEnum automatically represent as their name.

if current_status == "in_progress":
    print("The status is In Progress (string comparison).")  # Output: The status is In Progress (string comparison)

Conclusion

Enums in Python offer robust options for managing constant values with named references. By leveraging Enum, Flag, and StrEnum, your code can achieve greater clarity and prevent erroneous data processing. Whether you're exploring basic usage or advanced functionality, enums form a foundation that enhances code readability and maintainability, making them invaluable in Python programming.