Python - Python enum Module and Enumeration Types
Introduction
In Python, the enum module provides a way to create enumeration types, commonly called enums. An enumeration is a collection of named constants that represent a fixed set of related values. Instead of using unrelated numbers or strings throughout a program, developers can give meaningful names to those values.
For example, suppose an application represents the days of a week. Using numbers such as 1, 2, and 3 may make the code difficult to understand. With an enumeration, we can define MONDAY, TUESDAY, and WEDNESDAY as named members. This makes programs easier to read, maintain, and debug.
Python's enum module is available as part of the standard library, so it does not require an external package.
Importing the enum Module
The most commonly used class from the module is Enum.
from enum import Enum
We can then create an enumeration by defining a class that inherits from Enum.
from enum import Enum
class Color(Enum):
RED = 1
GREEN = 2
BLUE = 3
Here, Color is an enumeration and RED, GREEN, and BLUE are its members.
Each member has both a name and a value.
print(Color.RED)
print(Color.RED.name)
print(Color.RED.value)
Output:
Color.RED
RED
1
The name is RED, while its associated value is 1.
Why Use Enumerations?
Enums are useful when a variable should contain one value from a predefined collection of choices.
For example, an employee management application might have different employee statuses:
from enum import Enum
class EmployeeStatus(Enum):
ACTIVE = "active"
INACTIVE = "inactive"
ON_LEAVE = "on_leave"
Instead of repeatedly writing strings such as "active" or "inactive", the program can use:
EmployeeStatus.ACTIVE
This makes the intention of the code clearer.
Enums are particularly useful when:
-
A program has a fixed set of choices.
-
Values have meaningful names.
-
Developers want to avoid arbitrary constants.
-
Code readability is important.
-
The same set of values is used in multiple places.
Accessing Enum Members
Members can be accessed using the class name and member name.
from enum import Enum
class Direction(Enum):
NORTH = 1
SOUTH = 2
EAST = 3
WEST = 4
print(Direction.NORTH)
print(Direction.SOUTH)
The output is:
Direction.NORTH
Direction.SOUTH
The value of an enum member can be obtained using .value.
print(Direction.NORTH.value)
Output:
1
The name can be obtained using .name.
print(Direction.NORTH.name)
Output:
NORTH
Iterating Over an Enum
Enum members can be iterated over using a for loop.
from enum import Enum
class Season(Enum):
SPRING = 1
SUMMER = 2
AUTUMN = 3
WINTER = 4
for season in Season:
print(season)
Output:
Season.SPRING
Season.SUMMER
Season.AUTUMN
Season.WINTER
To display both names and values:
for season in Season:
print(season.name, season.value)
Output:
SPRING 1
SUMMER 2
AUTUMN 3
WINTER 4
This is useful when an application needs to process every possible option in an enumeration.
Comparing Enum Members
Enum members can be compared with one another.
from enum import Enum
class Status(Enum):
SUCCESS = 1
FAILURE = 2
print(Status.SUCCESS == Status.SUCCESS)
print(Status.SUCCESS == Status.FAILURE)
Output:
True
False
An important point is that enum members are not simply ordinary integers or strings.
For example:
class Status(Enum):
SUCCESS = 1
Then:
Status.SUCCESS == 1
is False.
This distinction helps prevent accidental comparisons between unrelated types.
Enum Values Can Be Strings
Enum values do not have to be integers. Strings can also be used.
from enum import Enum
class Language(Enum):
PYTHON = "Python"
JAVA = "Java"
CPP = "C++"
We can access the values as follows:
print(Language.PYTHON.value)
Output:
Python
String-based enums are particularly useful when working with configuration values, API responses, database fields, or application states.
Creating an Enum from a Value
Python allows us to retrieve an enum member using its value.
from enum import Enum
class Priority(Enum):
LOW = 1
MEDIUM = 2
HIGH = 3
priority = Priority(2)
print(priority)
Output:
Priority.MEDIUM
This is useful when a program receives a value from an external source and needs to convert it into a meaningful enum member.
If the value does not exist, Python raises a ValueError.
Priority(5)
This produces an error because 5 is not associated with any member of Priority.
Enum Aliases
Python allows multiple enum names to have the same value.
from enum import Enum
class Status(Enum):
SUCCESS = 1
COMPLETED = 1
FAILURE = 2
Here, SUCCESS and COMPLETED have the same value. COMPLETED becomes an alias of SUCCESS.
print(Status.SUCCESS)
print(Status.COMPLETED)
Both refer to the same enum member.
To obtain only the unique members and ignore aliases, iteration over the enum is useful.
Automatically Assigning Values with auto()
Python provides auto() for automatically generating enum values.
from enum import Enum, auto
class TaskStatus(Enum):
PENDING = auto()
RUNNING = auto()
COMPLETED = auto()
FAILED = auto()
Python automatically assigns values to these members.
This is useful when the exact numeric values are not important and only the uniqueness of the members matters.
IntEnum
Python also provides IntEnum. It is similar to Enum, but its members are also instances of int.
from enum import IntEnum
class Priority(IntEnum):
LOW = 1
MEDIUM = 2
HIGH = 3
Because Priority inherits from IntEnum, its members can participate in integer-oriented operations and comparisons.
print(Priority.HIGH == 3)
Output:
True
IntEnum can be useful when working with older systems, APIs, or libraries that expect integer values while the application still benefits from meaningful enum names.
However, ordinary Enum should generally be preferred when integer compatibility is not specifically required because it provides stronger separation between the enumeration and raw integers.
StrEnum
Modern versions of Python also provide StrEnum, which is designed for string-based enumeration members.
from enum import StrEnum
class Environment(StrEnum):
DEVELOPMENT = "development"
TESTING = "testing"
PRODUCTION = "production"
This is useful when enum members need to behave naturally as strings while still providing named constants.
The availability of StrEnum depends on the Python version, so code intended for older Python versions may use other approaches.
Flag and IntFlag
The enum module also includes Flag and IntFlag. These are useful when multiple options need to be combined using bitwise operations.
For example:
from enum import Flag, auto
class Permission(Flag):
READ = auto()
WRITE = auto()
EXECUTE = auto()
Permissions can then be combined:
user_permission = Permission.READ | Permission.WRITE
The resulting value represents both permissions.
This approach is commonly useful for permission systems, feature flags, configuration options, and other situations where multiple independent choices can be enabled simultaneously.
Using Enums in Conditional Statements
Enums can make conditional logic easier to understand.
from enum import Enum
class TrafficLight(Enum):
RED = 1
YELLOW = 2
GREEN = 3
light = TrafficLight.GREEN
if light == TrafficLight.RED:
print("Stop")
elif light == TrafficLight.YELLOW:
print("Prepare to stop")
elif light == TrafficLight.GREEN:
print("Go")
The code is more descriptive than checking unexplained numeric values such as 1, 2, and 3.
Enums in Functions
Enums can also be passed to functions.
from enum import Enum
class PaymentStatus(Enum):
PENDING = 1
PAID = 2
FAILED = 3
def process_payment(status):
if status == PaymentStatus.PAID:
print("Payment completed")
elif status == PaymentStatus.PENDING:
print("Payment is pending")
elif status == PaymentStatus.FAILED:
print("Payment failed")
process_payment(PaymentStatus.PAID)
This improves the readability of function calls because the argument clearly communicates its intended meaning.
Adding Methods to an Enum
An enum is a class, so methods can be defined inside it.
from enum import Enum
class OrderStatus(Enum):
PENDING = 1
SHIPPED = 2
DELIVERED = 3
def is_completed(self):
return self == OrderStatus.DELIVERED
We can use the method like this:
status = OrderStatus.DELIVERED
print(status.is_completed())
Output:
True
This allows related behavior to be kept together with the enumeration.
Advantages of Python Enums
Enums provide several advantages.
Improved readability: Meaningful names such as PaymentStatus.PAID are easier to understand than arbitrary values such as 2.
Reduced errors: Using predefined members can prevent accidental use of unsupported values.
Better maintainability: If the available choices change, they can be managed centrally in the enum definition.
Clearer code: Enums communicate the expected set of values directly.
Reusable constants: The same enum can be used throughout multiple functions and classes.
Type distinction: Standard Enum members are distinct from their underlying values, which can prevent unintended comparisons.
Important Considerations
Enums are most appropriate when the possible values form a relatively fixed set. They should not be used simply because a program contains constants.
For example, if an application has hundreds of values that change frequently, an enum may not be the most suitable solution.
It is also important to distinguish between Enum, IntEnum, Flag, and IntFlag. Standard Enum provides stronger separation from ordinary values, while the integer-based variants are useful when compatibility with integer operations is required.
Practical Example
Consider an online order management system:
from enum import Enum
class OrderStatus(Enum):
PLACED = "placed"
PROCESSING = "processing"
SHIPPED = "shipped"
DELIVERED = "delivered"
CANCELLED = "cancelled"
def display_status(status):
if status == OrderStatus.PLACED:
print("Order has been placed.")
elif status == OrderStatus.PROCESSING:
print("Order is being processed.")
elif status == OrderStatus.SHIPPED:
print("Order has been shipped.")
elif status == OrderStatus.DELIVERED:
print("Order has been delivered.")
elif status == OrderStatus.CANCELLED:
print("Order has been cancelled.")
current_status = OrderStatus.SHIPPED
display_status(current_status)
Output:
Order has been shipped.
Here, the program has a clearly defined set of valid order statuses. Instead of passing arbitrary strings throughout the application, the OrderStatus enum provides a controlled and readable representation of these states.
Conclusion
Python's enum module is an effective way to represent a fixed collection of related named values. It provides more structure and clarity than using unrelated integer or string constants. Developers can access enum members by name, retrieve their values, iterate through them, compare them, and use them in functions and conditional statements.
The module also provides specialized types such as IntEnum, StrEnum, Flag, and IntFlag for situations where integer, string, or combination-based behavior is required. By choosing the appropriate enumeration type, Python programs can become more readable, maintainable, and less prone to errors.