Skip to main content

enum — Support for Enumerations

📚 Official Documentation & Resources

Primary Official Sources (REQUIRED)

Additional Authoritative Sources

IMPORTANT: Examples in this guide are adapted from the official Python documentation at https://docs.python.org/3/library/enum.html

Overview

The enum module defines enumeration classes that provide a way to create symbolic names bound to unique values. Enumerations are a set of named constants that belong to a common type. They provide a readable and maintainable alternative to using magic numbers or string constants throughout your code.

The module was introduced in Python 3.4 (PEP 435) and has been enhanced with additional functionality in subsequent versions. It supports various enumeration types including basic enums, integer enums, flags, and auto-generated values.

🎯 Key Characteristics

  • Type Safety: Enum members are distinct types, preventing invalid comparisons
  • Immutable: Enum members cannot be modified after creation
  • Hashable: Can be used as dictionary keys and in sets
  • Iterable: Can iterate over enum members in definition order
  • Unique Values: Optional enforcement of unique values across members
  • Auto Generation: Automatic value assignment with auto()

🔧 Prerequisites and Setup

Python Version Compatibility

  • Minimum Python version required: Python 3.4+ (module introduction)
  • Enhanced features: Python 3.6+ (ordered enumeration)
  • Latest improvements: Python 3.11+ (additional enum features)

Installation and Imports

# Standard library (no installation needed)
import enum
from enum import Enum, IntEnum, Flag, IntFlag, auto, unique

📚 Basic Usage

Official Documentation Examples

Source: All examples adapted from https://docs.python.org/3/library/enum.html

Simple Example

from enum import Enum

# Basic enumeration (from official docs)
class Color(Enum):
RED = 1
GREEN = 2
BLUE = 3

# Usage
print(Color.RED) # Color.RED
print(Color.RED.name) # 'RED'
print(Color.RED.value) # 1
print(repr(Color.RED)) # <Color.RED: 1>

# Comparison
print(Color.RED == Color.RED) # True
print(Color.RED == Color.BLUE) # False
print(Color.RED == 1) # False (type safety)

# Iteration
for color in Color:
print(f"{color.name}: {color.value}")

Core Methods/Functions

from enum import Enum, auto

# Using auto() for automatic value assignment (from official docs)
class Direction(Enum):
NORTH = auto()
SOUTH = auto()
EAST = auto()
WEST = auto()

print(list(Direction)) # [<Direction.NORTH: 1>, <Direction.SOUTH: 2>, ...]

# Functional API (from official docs)
Animal = Enum('Animal', 'DOG CAT BIRD')
print(Animal.DOG) # <Animal.DOG: 1>
print(Animal.DOG.name) # 'DOG'

# Alternative functional syntax
Planet = Enum('Planet', [
('MERCURY', 1),
('VENUS', 2),
('EARTH', 3)
])

Common Patterns

# Pattern 1: String enums (from official docs)
from enum import Enum

class Status(Enum):
PENDING = "pending"
APPROVED = "approved"
REJECTED = "rejected"

def __str__(self):
return self.value

print(str(Status.PENDING)) # 'pending'
print(Status.PENDING.value) # 'pending'

# Pattern 2: Integer enums (from official docs)
from enum import IntEnum

class Priority(IntEnum):
LOW = 1
MEDIUM = 2
HIGH = 3
CRITICAL = 4

# IntEnum allows comparison with integers
print(Priority.HIGH == 3) # True
print(Priority.HIGH > Priority.LOW) # True

# Pattern 3: Functional behavior (from official docs)
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
self.radius = radius

@property
def surface_gravity(self):
G = 6.67300E-11
return G * self.mass / (self.radius * self.radius)

print(f"Earth gravity: {Planet.EARTH.surface_gravity:.2f}")

🔧 enum API Reference

Core Enum Classes

ClassDescriptionExample
EnumBase enumeration classclass Color(Enum): RED = 1
IntEnumInteger-compatible enumclass Priority(IntEnum): HIGH = 1
FlagBitwise combinable enumclass Permission(Flag): READ = 1
IntFlagInteger flag enumclass FileMode(IntFlag): READ = 1

Enum Member Properties

PropertyDescriptionTypeExample
nameMember namestrColor.RED.name → 'RED'
valueMember valueAnyColor.RED.value → 1

Enum Class Methods

MethodDescriptionReturn TypeExample
__members__Ordered mapping of names to membersMappingProxyColor.__members__
__iter__()Iterate over enum membersIteratorfor c in Color: ...
__len__()Number of membersintlen(Color)
__getitem__(name)Get member by nameEnumMemberColor['RED']
__call__(value)Get member by valueEnumMemberColor(1)

Decorators and Functions

FunctionDescriptionExample
@uniqueEnsure all values are unique@unique class Color(Enum): ...
auto()Generate automatic valuesRED = auto()
Enum(name, names)Functional APIColor = Enum('Color', 'RED GREEN BLUE')

Detailed Method Examples

Basic Enumeration Operations

from enum import Enum

# Official docs example: Basic operations
class Color(Enum):
RED = 1
GREEN = 2
BLUE = 3

# Member access
red = Color.RED
print(f"Name: {red.name}, Value: {red.value}") # Name: RED, Value: 1

# Different ways to access members
print(Color.RED) # <Color.RED: 1>
print(Color['RED']) # <Color.RED: 1>
print(Color(1)) # <Color.RED: 1>

# Membership testing
print(Color.RED in Color) # True
print('RED' in Color.__members__) # True

# Iteration
print("All colors:")
for color in Color:
print(f" {color.name} = {color.value}")

Auto and Unique Values

from enum import Enum, auto, unique

# Official docs example: Using auto()
class Direction(Enum):
NORTH = auto()
SOUTH = auto()
EAST = auto()
WEST = auto()

print(f"North value: {Direction.NORTH.value}") # North value: 1

# Ensuring unique values
@unique
class Color(Enum):
RED = 1
GREEN = 2
BLUE = 3
# CRIMSON = 1 # This would raise ValueError due to @unique

# Custom auto() behavior
class AutoName(Enum):
def _generate_next_value_(name, start, count, last_values):
return name.lower()

class Status(AutoName):
PENDING = auto() # value will be 'pending'
APPROVED = auto() # value will be 'approved'

print(f"Status: {Status.PENDING.value}") # Status: pending

IntEnum and Comparisons

from enum import IntEnum

# Official docs example: IntEnum
class Priority(IntEnum):
LOW = 1
MEDIUM = 2
HIGH = 3

# IntEnum members can be compared to integers
print(Priority.HIGH == 3) # True
print(Priority.HIGH > 2) # True
print(Priority.HIGH + 1) # 4

# Sorting works with IntEnum
priorities = [Priority.HIGH, Priority.LOW, Priority.MEDIUM]
priorities.sort()
print(priorities) # [<Priority.LOW: 1>, <Priority.MEDIUM: 2>, <Priority.HIGH: 3>]

# But still maintain enum semantics
print(isinstance(Priority.HIGH, Priority)) # True
print(Priority.HIGH.name) # 'HIGH'

Flag Enumerations

from enum import Flag, auto

# Official docs example: Flag enum for bitwise operations
class Permission(Flag):
READ = auto()
WRITE = auto()
EXECUTE = auto()

# Combine flags
rw = Permission.READ | Permission.WRITE
print(rw) # <Permission.WRITE|READ: 3>

# Check for permissions
print(Permission.READ in rw) # True
print(Permission.EXECUTE in rw) # False

# All combinations
all_perms = Permission.READ | Permission.WRITE | Permission.EXECUTE
print(all_perms) # <Permission.EXECUTE|WRITE|READ: 7>

# Remove permissions
no_write = all_perms & ~Permission.WRITE
print(no_write) # <Permission.EXECUTE|READ: 5>

Complex Enums with Methods

from enum import Enum

# Official docs example: Planet enum with calculations
class Planet(Enum):
MERCURY = (3.303e+23, 2.4397e6)
VENUS = (4.869e+24, 6.0518e6)
EARTH = (5.976e+24, 6.37814e6)
MARS = (6.421e+23, 3.3972e6)

def __init__(self, mass, radius):
self.mass = mass # in kilograms
self.radius = radius # in meters

@property
def surface_gravity(self):
# universal gravitational constant (m3 kg-1 s-2)
G = 6.67300E-11
return G * self.mass / (self.radius * self.radius)

# Usage
earth = Planet.EARTH
print(f"Earth's surface gravity: {earth.surface_gravity:.2f} m/s²")

# Compare planets
for planet in Planet:
print(f"{planet.name}: {planet.surface_gravity:.2f} m/s²")

Functional API

from enum import Enum

# Official docs example: Creating enums functionally
Animal = Enum('Animal', 'DOG CAT BIRD')
print(Animal.DOG) # <Animal.DOG: 1>
print(Animal.CAT.value) # 2

# With specific values
Color = Enum('Color', [('RED', 1), ('GREEN', 2), ('BLUE', 3)])
print(Color.RED.value) # 1

# From string
Status = Enum('Status', 'PENDING APPROVED REJECTED')
print(list(Status)) # [<Status.PENDING: 1>, <Status.APPROVED: 2>, <Status.REJECTED: 3>]

# From dictionary
HttpStatus = Enum('HttpStatus', {
'OK': 200,
'NOT_FOUND': 404,
'SERVER_ERROR': 500
})
print(HttpStatus.OK.value) # 200

Custom Enum Behaviors

from enum import Enum

# Official docs example: Custom string representation
class Color(Enum):
RED = 1
GREEN = 2
BLUE = 3

def __str__(self):
return f'Color.{self.name}'

def __repr__(self):
return f'{self.__class__.__name__}.{self.name}'

print(str(Color.RED)) # Color.RED
print(repr(Color.RED)) # Color.RED

# Custom comparison behavior
class Grade(Enum):
A = 90
B = 80
C = 70
D = 60
F = 0

def __lt__(self, other):
if self.__class__ is other.__class__:
return self.value < other.value
return NotImplemented

def __le__(self, other):
if self.__class__ is other.__class__:
return self.value <= other.value
return NotImplemented

print(Grade.B < Grade.A) # True
print(Grade.A <= Grade.A) # True

Important Notes

Performance Considerations

  • Enum member lookup is O(1) for both name and value access
  • Iteration over enum members is O(n) where n is the number of members
  • Flag operations are bitwise and very fast
  • Memory usage is minimal as members are singletons

Common Gotchas

from enum import Enum

# Gotcha 1: Enum members are singletons
class Color(Enum):
RED = 1
GREEN = 2

# These are the same object
assert Color.RED is Color.RED
assert Color(1) is Color.RED

# Gotcha 2: Cannot extend enums with members
class MoreColors(Color): # ValueError if Color has members
pass # Can only extend empty enum classes

# Gotcha 3: Aliases (same value = alias)
class Status(Enum):
PENDING = 1
WAITING = 1 # This is an alias for PENDING

print(Status.WAITING is Status.PENDING) # True
print(list(Status)) # Only shows [<Status.PENDING: 1>]

Best Practices

# 1. Use descriptive names
class HttpStatus(Enum):
OK = 200
NOT_FOUND = 404
SERVER_ERROR = 500

# 2. Use auto() when values don't matter
class Direction(Enum):
NORTH = auto()
SOUTH = auto()
EAST = auto()
WEST = auto()

# 3. Use @unique when all values should be distinct
from enum import unique

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

# 4. Use IntEnum sparingly - only when you need integer behavior
from enum import IntEnum

class Priority(IntEnum):
LOW = 1
MEDIUM = 2
HIGH = 3

# 5. Document complex enum behaviors
class Planet(Enum):
"""Planetary data with calculated properties."""
EARTH = (5.976e+24, 6.37814e6)

def __init__(self, mass, radius):
"""Initialize planet with mass (kg) and radius (m)."""
self.mass = mass
self.radius = radius

Thread Safety

  • Enum classes and members are immutable and thread-safe
  • Multiple threads can safely access enum members simultaneously
  • Enum creation itself should be done at module level, not in threaded code

Serialization

import json
import pickle
from enum import Enum

class Status(Enum):
PENDING = "pending"
APPROVED = "approved"

# Pickle serialization works out of the box
status = Status.PENDING
pickled = pickle.dumps(status)
unpickled = pickle.loads(pickled)
assert status is unpickled

# JSON requires custom handling
def enum_serializer(obj):
if isinstance(obj, Enum):
return obj.value
raise TypeError(f"Object {obj} is not JSON serializable")

json_data = json.dumps(Status.PENDING, default=enum_serializer)
print(json_data) # '"pending"'
  • types: For type-related utilities and type checking
  • collections: For OrderedDict and other container types
  • dataclasses: For data classes (alternative to enums for some use cases)
  • typing: For type hints and annotations with enums