The enum module provides type-safe enumerations. No more magic strings or mysterious integers scattered through your code.
Basic Enum
from enum import Enum
class Color(Enum):
RED = 1
GREEN = 2
BLUE = 3
# Usage
color = Color.RED
print(color) # Color.RED
print(color.name) # 'RED'
print(color.value) # 1
# Comparison
if color == Color.RED:
print("It's red")
# Iteration
for c in Color:
print(c)auto() for Automatic Values
from enum import Enum, auto
class Status(Enum):
PENDING = auto() # 1
RUNNING = auto() # 2
COMPLETE = auto() # 3
FAILED = auto() # 4Use when you don't care about specific values.
String Enums
from enum import Enum
class HttpMethod(Enum):
GET = "GET"
POST = "POST"
PUT = "PUT"
DELETE = "DELETE"
# Lookup by value
method = HttpMethod("GET")
print(method) # HttpMethod.GET
# Use in API calls
requests.request(HttpMethod.POST.value, url)Python 3.11+ has StrEnum:
from enum import StrEnum
class HttpMethod(StrEnum):
GET = "GET"
POST = "POST"
# Automatically converts to string
print(f"Method: {HttpMethod.GET}") # "Method: GET"IntEnum: Integer-Compatible
from enum import IntEnum
class Priority(IntEnum):
LOW = 1
MEDIUM = 2
HIGH = 3
# Works like an integer
print(Priority.HIGH > Priority.LOW) # True
print(Priority.MEDIUM + 1) # 3Caution: IntEnum compares equal to plain integers:
Priority.LOW == 1 # True (sometimes surprising)Regular Enum doesn't:
Color.RED == 1 # FalseFlag: Combinable Enums
from enum import Flag, auto
class Permission(Flag):
READ = auto()
WRITE = auto()
EXECUTE = auto()
# Combine with |
user_perms = Permission.READ | Permission.WRITE
# Check with &
if Permission.READ in user_perms:
print("Can read")
# Check multiple
if user_perms & (Permission.READ | Permission.WRITE):
print("Can read or write")Enum Methods
Add methods to enums:
from enum import Enum
class Planet(Enum):
MERCURY = (3.303e+23, 2.4397e6)
EARTH = (5.976e+24, 6.37814e6)
MARS = (6.421e+23, 3.3972e6)
def __init__(self, mass, radius):
self.mass = mass
self.radius = radius
@property
def surface_gravity(self):
G = 6.67430e-11
return G * self.mass / (self.radius ** 2)
print(Planet.EARTH.surface_gravity) # 9.8...Lookup Patterns
from enum import Enum
class Status(Enum):
ACTIVE = "active"
INACTIVE = "inactive"
PENDING = "pending"
# By name
Status["ACTIVE"] # Status.ACTIVE
# By value
Status("active") # Status.ACTIVE
# Safe lookup
def get_status(value: str) -> Status | None:
try:
return Status(value)
except ValueError:
return NoneEnsuring Unique Values
from enum import Enum, unique
@unique
class ErrorCode(Enum):
NOT_FOUND = 404
SERVER_ERROR = 500
# DUPLICATE = 404 # Would raise ValueErrorAliases
Without @unique, duplicates create aliases:
from enum import Enum
class Status(Enum):
RUNNING = 1
STARTED = 1 # Alias for RUNNING
print(Status.STARTED is Status.RUNNING) # True
print(list(Status)) # [Status.RUNNING] - only canonicalPractical Examples
State Machine
from enum import Enum, auto
class OrderState(Enum):
CREATED = auto()
PAID = auto()
SHIPPED = auto()
DELIVERED = auto()
CANCELLED = auto()
def can_transition_to(self, new_state):
valid = {
OrderState.CREATED: {OrderState.PAID, OrderState.CANCELLED},
OrderState.PAID: {OrderState.SHIPPED, OrderState.CANCELLED},
OrderState.SHIPPED: {OrderState.DELIVERED},
OrderState.DELIVERED: set(),
OrderState.CANCELLED: set(),
}
return new_state in valid[self]
order_state = OrderState.CREATED
if order_state.can_transition_to(OrderState.PAID):
order_state = OrderState.PAIDConfiguration Options
from enum import Enum
class LogLevel(Enum):
DEBUG = 10
INFO = 20
WARNING = 30
ERROR = 40
CRITICAL = 50
def should_log(self, message_level: 'LogLevel') -> bool:
return message_level.value >= self.value
config_level = LogLevel.WARNING
if config_level.should_log(LogLevel.ERROR):
print("Logging error")Database Values
from enum import Enum
class UserRole(Enum):
ADMIN = "admin"
EDITOR = "editor"
VIEWER = "viewer"
# SQLAlchemy column
# role = Column(SQLEnum(UserRole))
# Pydantic model
# class User(BaseModel):
# role: UserRoleQuick Reference
from enum import Enum, IntEnum, Flag, StrEnum, auto, unique
# Basic enum
class Color(Enum):
RED = 1
# Auto values
class Status(Enum):
PENDING = auto()
# Integer-compatible
class Priority(IntEnum):
LOW = 1
# Combinable flags
class Perm(Flag):
READ = auto()
# String enum (3.11+)
class Method(StrEnum):
GET = "GET"
# Ensure unique values
@unique
class Code(Enum):
OK = 200| Type | Use Case |
|---|---|
Enum | General purpose, type-safe |
IntEnum | Need integer comparison |
StrEnum | Need string conversion |
Flag | Combinable bit flags |
Enums make your code self-documenting. Use them instead of magic strings and numbers.
React to this post: