Enums replace magic strings and integers with type-safe, self-documenting constants. Essential for configuration, state machines, and API design.
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
color == Color.RED # True
color == 1 # False (use .value for int comparison)String Enums
from enum import Enum
class Status(str, Enum):
PENDING = "pending"
ACTIVE = "active"
COMPLETED = "completed"
# Works as string
status = Status.ACTIVE
print(f"Status: {status}") # Status: active
print(status == "active") # True (because str mixin)
# JSON serializable
import json
json.dumps({"status": status}) # '{"status": "active"}'Auto Values
from enum import Enum, auto
class Priority(Enum):
LOW = auto() # 1
MEDIUM = auto() # 2
HIGH = auto() # 3
CRITICAL = auto() # 4
# Custom auto
class HttpMethod(Enum):
def _generate_next_value_(name, start, count, last_values):
return name.upper()
GET = auto() # 'GET'
POST = auto() # 'POST'
PUT = auto() # 'PUT'
DELETE = auto() # 'DELETE'IntEnum for Integer Operations
from enum import IntEnum
class Permission(IntEnum):
READ = 4
WRITE = 2
EXECUTE = 1
# Works with integers
perm = Permission.READ
print(perm + Permission.WRITE) # 6
print(perm > Permission.WRITE) # True
print(perm == 4) # TrueFlag Enum for Bitwise Operations
from enum import Flag, auto
class Permissions(Flag):
NONE = 0
READ = auto() # 1
WRITE = auto() # 2
EXECUTE = auto() # 4
# Combinations
READ_WRITE = READ | WRITE
ALL = READ | WRITE | EXECUTE
# Combine flags
perms = Permissions.READ | Permissions.WRITE
print(perms) # Permissions.READ|WRITE
# Check flags
Permissions.READ in perms # True
Permissions.EXECUTE in perms # False
# Iterate combined flags
for perm in perms:
print(perm) # Permissions.READ, Permissions.WRITEEnum Methods
from enum import Enum
class HttpStatus(Enum):
OK = 200
NOT_FOUND = 404
SERVER_ERROR = 500
def is_success(self) -> bool:
return 200 <= self.value < 300
def is_error(self) -> bool:
return self.value >= 400
@classmethod
def from_code(cls, code: int) -> 'HttpStatus':
for status in cls:
if status.value == code:
return status
raise ValueError(f"Unknown status code: {code}")
status = HttpStatus.OK
print(status.is_success()) # True
status = HttpStatus.from_code(404)
print(status) # HttpStatus.NOT_FOUNDEnum with Properties
from enum import Enum
class Planet(Enum):
MERCURY = (3.303e+23, 2.4397e6)
VENUS = (4.869e+24, 6.0518e6)
EARTH = (5.976e+24, 6.37814e6)
def __init__(self, mass, radius):
self.mass = mass # kg
self.radius = radius # meters
@property
def surface_gravity(self):
G = 6.67430e-11
return G * self.mass / (self.radius ** 2)
print(Planet.EARTH.surface_gravity) # ~9.8State 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: 'OrderState') -> bool:
transitions = {
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 transitions[self]
class Order:
def __init__(self):
self.state = OrderState.CREATED
def transition(self, new_state: OrderState):
if not self.state.can_transition_to(new_state):
raise ValueError(f"Cannot transition from {self.state} to {new_state}")
self.state = new_state
order = Order()
order.transition(OrderState.PAID)
order.transition(OrderState.SHIPPED)
# order.transition(OrderState.CREATED) # ValueError!Lookup by Name or Value
from enum import Enum
class Direction(Enum):
NORTH = "N"
SOUTH = "S"
EAST = "E"
WEST = "W"
# By name
Direction["NORTH"] # Direction.NORTH
Direction["INVALID"] # KeyError
# By value
Direction("N") # Direction.NORTH
Direction("X") # ValueError
# Safe lookup
def get_direction(value: str) -> Direction | None:
try:
return Direction(value)
except ValueError:
return NoneIteration and Membership
from enum import Enum
class Color(Enum):
RED = 1
GREEN = 2
BLUE = 3
# Iterate all members
for color in Color:
print(f"{color.name}: {color.value}")
# Check membership
Color.RED in Color # True
# Get all values
list(Color) # [Color.RED, Color.GREEN, Color.BLUE]
# Length
len(Color) # 3Aliases
from enum import Enum
class Color(Enum):
RED = 1
CRIMSON = 1 # Alias for RED
GREEN = 2
BLUE = 3
Color.RED is Color.CRIMSON # True
# Only canonical members in iteration
list(Color) # [Color.RED, Color.GREEN, Color.BLUE]
# Access all including aliases
Color.__members__
# {'RED': Color.RED, 'CRIMSON': Color.RED, 'GREEN': Color.GREEN, 'BLUE': Color.BLUE}Unique Decorator
from enum import Enum, unique
@unique
class Color(Enum):
RED = 1
GREEN = 2
BLUE = 3
# CRIMSON = 1 # Would raise ValueError!Configuration Enum
from enum import Enum
class Environment(str, Enum):
DEVELOPMENT = "development"
STAGING = "staging"
PRODUCTION = "production"
@property
def debug(self) -> bool:
return self == Environment.DEVELOPMENT
@property
def database_url(self) -> str:
urls = {
Environment.DEVELOPMENT: "sqlite:///dev.db",
Environment.STAGING: "postgres://staging-db/app",
Environment.PRODUCTION: "postgres://prod-db/app",
}
return urls[self]
env = Environment.DEVELOPMENT
print(env.debug) # True
print(env.database_url) # sqlite:///dev.dbAPI Response Types
from enum import Enum
from typing import TypedDict
class ErrorCode(str, Enum):
NOT_FOUND = "NOT_FOUND"
UNAUTHORIZED = "UNAUTHORIZED"
VALIDATION_ERROR = "VALIDATION_ERROR"
INTERNAL_ERROR = "INTERNAL_ERROR"
@property
def http_status(self) -> int:
mapping = {
ErrorCode.NOT_FOUND: 404,
ErrorCode.UNAUTHORIZED: 401,
ErrorCode.VALIDATION_ERROR: 400,
ErrorCode.INTERNAL_ERROR: 500,
}
return mapping[self]
@property
def message(self) -> str:
messages = {
ErrorCode.NOT_FOUND: "Resource not found",
ErrorCode.UNAUTHORIZED: "Authentication required",
ErrorCode.VALIDATION_ERROR: "Invalid input",
ErrorCode.INTERNAL_ERROR: "Internal server error",
}
return messages[self]Serialization
from enum import Enum
import json
class Status(str, Enum):
ACTIVE = "active"
INACTIVE = "inactive"
# JSON encode
data = {"status": Status.ACTIVE}
json.dumps(data) # '{"status": "active"}'
# Custom encoder for non-string enums
class EnumEncoder(json.JSONEncoder):
def default(self, obj):
if isinstance(obj, Enum):
return obj.value
return super().default(obj)
class Priority(Enum):
LOW = 1
HIGH = 2
json.dumps({"priority": Priority.HIGH}, cls=EnumEncoder)
# '{"priority": 2}'Enums make your code self-documenting and catch errors at the type level. Use them anywhere you have a fixed set of related constants.
React to this post: