- What are Enums — a way to define a set of named constants
- Why use them — cleaner code, prevent errors, better readability
- Basic usage — creating and using enums
- Enum members — accessing and comparing enum values
- Auto values — automatically assigning values
- Real-world use — practical examples you can use
What are Enums?
An Enum (short for enumeration) is a way to define a set of named constants. It's like a list of choices where each choice has a name and a value.
Think of Enums like a drop-down menu on a website. Instead of typing something that might be wrong, you pick from a fixed set of valid options. This prevents mistakes and makes your code more reliable.
For example, instead of using strings like "Monday", "Tuesday", etc., you can use an Enum called Day with members MONDAY, TUESDAY, etc. This way, you can't accidentally type "Monady" and cause a bug.
💡 Key concept: Enums are a way to create a fixed set of named values. They make your code more readable, more reliable, and easier to maintain.
Why Use Enums?
The Benefits of Enums
Enums make your code better in several ways. Let's see why you should use them.
# Why Use Enums?
print("=" * 50)
print("WHY USE ENUMS?")
print("=" * 50)
# ============================================================
# WITHOUT ENUMS — Using Strings (Error-Prone)
# ============================================================
print("\n1. WITHOUT ENUMS (Using Strings)")
def get_status_color(status):
if status == "active":
return "green"
elif status == "inactive":
return "gray"
elif status == "pending":
return "yellow"
elif status == "archived":
return "blue"
else:
return "red" # Unknown status
# Problems:
# 1. We can pass any string, even invalid ones
# 2. No autocomplete in IDEs
# 3. Can't see all possible values easily
# 4. Typing errors cause bugs (e.g., "actve" instead of "active")
print(" get_status_color('active') ->", get_status_color("active"))
print(" get_status_color('actve') ->", get_status_color("actve")) # Bug!
print(" get_status_color('unknown') ->", get_status_color("unknown"))
# ============================================================
# WITH ENUMS — Clean and Safe
# ============================================================
print("\n2. WITH ENUMS (Clean and Safe)")
from enum import Enum
class Status(Enum):
ACTIVE = "active"
INACTIVE = "inactive"
PENDING = "pending"
ARCHIVED = "archived"
def get_status_color_enum(status):
if status == Status.ACTIVE:
return "green"
elif status == Status.INACTIVE:
return "gray"
elif status == Status.PENDING:
return "yellow"
elif status == Status.ARCHIVED:
return "blue"
else:
return "red"
# Benefits:
# 1. Only valid statuses can be used
# 2. IDEs provide autocomplete
# 3. All possible values are defined in one place
# 4. No typing errors
print(" get_status_color_enum(Status.ACTIVE) ->", get_status_color_enum(Status.ACTIVE))
# This would cause an error:
# print(get_status_color_enum(Status.UNKNOWN)) # AttributeError
# ============================================================
# THE BENEFITS
# ============================================================
print("\n" + "-" * 30)
print("BENEFITS OF ENUMS")
print("-" * 30)
print("""
- Prevents invalid values
- Better IDE support (autocomplete)
- All constants in one place
- More readable code
- Prevents typing errors
- Self-documenting
- Can have associated values
- Works with type checking tools
""")
print("\n Enums are especially useful for:")
print(" - Status values")
print(" - Configurations")
print(" - Categories")
print(" - Options and settings")
Benefits of Enums:
- Prevents invalid values — only defined values are allowed
- Better IDE support — autocomplete works
- All constants in one place — easier to manage
- More readable code — names are self-explanatory
- Prevents typing errors — no typos in string constants
- Self-documenting — enum names explain the values
Quick Check: What is the main advantage of using Enums over strings? (Answer: Enums prevent invalid values and provide better IDE support)
Basic Usage
Creating and Using Enums
Creating an Enum is very simple. You just inherit from Enum and define your constants as class attributes.
# Basic Enum Usage
print("=" * 50)
print("BASIC ENUM USAGE")
print("=" * 50)
from enum import Enum
# ============================================================
# CREATING AN ENUM
# ============================================================
print("\n1. CREATING AN ENUM")
class Color(Enum):
RED = 1
GREEN = 2
BLUE = 3
# Each member is a constant
print(f" Color.RED: {Color.RED}")
print(f" Color.GREEN: {Color.GREEN}")
print(f" Color.BLUE: {Color.BLUE}")
# Members have names and values
print(f" Color.RED.name: {Color.RED.name}")
print(f" Color.RED.value: {Color.RED.value}")
# ============================================================
# ACCESSING ENUM MEMBERS
# ============================================================
print("\n2. ACCESSING ENUM MEMBERS")
class Status(Enum):
PENDING = "pending"
PROCESSING = "processing"
COMPLETED = "completed"
FAILED = "failed"
# Different ways to access enum members
print(" Status.PENDING:", Status.PENDING)
print(" Status['PENDING']:", Status['PENDING'])
print(" Status('pending'):", Status("pending"))
# Get the name and value
status = Status.PROCESSING
print(f" status.name: {status.name}")
print(f" status.value: {status.value}")
# ============================================================
# ITERATING OVER ENUMS
# ============================================================
print("\n3. ITERATING OVER ENUMS")
class Day(Enum):
MONDAY = 1
TUESDAY = 2
WEDNESDAY = 3
THURSDAY = 4
FRIDAY = 5
SATURDAY = 6
SUNDAY = 7
print(" All days:")
for day in Day:
print(f" {day.name}: {day.value}")
# Get a list of all values
all_days = list(Day)
print(f" List of days: {all_days}")
# ============================================================
# COMPARING ENUM MEMBERS
# ============================================================
print("\n4. COMPARING ENUM MEMBERS")
class Priority(Enum):
LOW = 1
MEDIUM = 2
HIGH = 3
p1 = Priority.LOW
p2 = Priority.MEDIUM
p3 = Priority.LOW
print(f" p1 == p3: {p1 == p3}")
print(f" p1 == p2: {p1 == p2}")
print(f" p1 is p3: {p1 is p3}")
print(f" p1 is p2: {p1 is p2}")
# Compare by value (using the value)
print(f" p1.value < p2.value: {p1.value < p2.value}")
# ============================================================
# USING ENUMS IN FUNCTIONS
# ============================================================
print("\n5. USING ENUMS IN FUNCTIONS")
def handle_order(status):
if status == Status.PENDING:
return "Order is waiting"
elif status == Status.PROCESSING:
return "Order is being processed"
elif status == Status.COMPLETED:
return "Order is complete"
elif status == Status.FAILED:
return "Order failed"
else:
return "Unknown status"
print(f" handle_order(Status.PENDING): {handle_order(Status.PENDING)}")
print(f" handle_order(Status.COMPLETED): {handle_order(Status.COMPLETED)}")
# ============================================================
# ENUM MEMBERS ARE SINGLETONS
# ============================================================
print("\n6. ENUM MEMBERS ARE SINGLETONS")
class Fruit(Enum):
APPLE = 1
BANANA = 2
ORANGE = 3
a1 = Fruit.APPLE
a2 = Fruit.APPLE
print(f" a1 is a2: {a1 is a2}")
print(f" id(a1) == id(a2): {id(a1) == id(a2)}")
Basic usage key points:
- Create —
class MyEnum(Enum):with constants - Access —
MyEnum.MEMBER,MyEnum['MEMBER'],MyEnum(value) - Iterate —
for member in MyEnum: - Compare — use
==oris - Members are singletons — each member exists only once
Quick Check: How do you access an enum member by its value? (Answer: MyEnum(value))
Enum Members
Understanding Enum Members
Enum members are special objects that have both a name and a value. They're more than just constants.
# Understanding Enum Members
print("=" * 50)
print("UNDERSTANDING ENUM MEMBERS")
print("=" * 50)
from enum import Enum
# ============================================================
# MEMBER PROPERTIES
# ============================================================
print("\n1. MEMBER PROPERTIES")
class Planet(Enum):
MERCURY = 1
VENUS = 2
EARTH = 3
MARS = 4
JUPITER = 5
SATURN = 6
URANUS = 7
NEPTUNE = 8
# Each member has name and value
earth = Planet.EARTH
print(f" Name: {earth.name}")
print(f" Value: {earth.value}")
# Members are instances of the enum class
print(f" Type: {type(earth)}")
print(f" Class: {earth.__class__}")
# ============================================================
# MEMBER DISPLAY
# ============================================================
print("\n2. MEMBER DISPLAY")
class Size(Enum):
SMALL = "S"
MEDIUM = "M"
LARGE = "L"
XL = "XL"
print(f" Size.SMALL: {Size.SMALL}")
print(f" Repr: {repr(Size.SMALL)}")
print(f" String: {str(Size.SMALL)}")
print(f" Name: {Size.SMALL.name}")
print(f" Value: {Size.SMALL.value}")
# ============================================================
# COMPARING WITH STRINGS
# ============================================================
print("\n3. COMPARING WITH STRINGS")
class OrderStatus(Enum):
PENDING = "pending"
PROCESSING = "processing"
COMPLETED = "completed"
status = OrderStatus.PROCESSING
# Compare with enum member (correct way)
print(f" status == OrderStatus.PROCESSING: {status == OrderStatus.PROCESSING}")
print(f" status is OrderStatus.PROCESSING: {status is OrderStatus.PROCESSING}")
# Compare with string (not recommended)
print(f" status.value == 'processing': {status.value == 'processing'}")
# ============================================================
# CHECKING IF A VALUE EXISTS
# ============================================================
print("\n4. CHECKING IF A VALUE EXISTS")
class ErrorCode(Enum):
NOT_FOUND = 404
SERVER_ERROR = 500
BAD_REQUEST = 400
# Check if a value exists
def is_valid_error_code(value):
try:
ErrorCode(value)
return True
except ValueError:
return False
print(f" is_valid_error_code(404): {is_valid_error_code(404)}")
print(f" is_valid_error_code(200): {is_valid_error_code(200)}")
# Get all values
all_codes = [member.value for member in ErrorCode]
print(f" All error codes: {all_codes}")
# ============================================================
# GETTING THE MEMBER FROM VALUE
# ============================================================
print("\n5. GETTING THE MEMBER FROM VALUE")
class Direction(Enum):
NORTH = 1
SOUTH = 2
EAST = 3
WEST = 4
# Get member by value
direction = Direction(2)
print(f" Direction(2): {direction}")
print(f" Direction(2).name: {direction.name}")
# Get member by name
direction = Direction['EAST']
print(f" Direction['EAST']: {direction}")
print(f" Direction['EAST'].value: {direction.value}")
# ============================================================
# ENUM WITH NAMES AS VALUES
# ============================================================
print("\n6. ENUM WITH NAMES AS VALUES")
from enum import Enum, auto
class AutoEnum(Enum):
FIRST = auto()
SECOND = auto()
THIRD = auto()
print(" Auto values:")
for member in AutoEnum:
print(f" {member.name} = {member.value}")
Enum members key points:
- name — the name of the member (string)
- value — the value of the member
- Comparison — use
==orisfor members - Lookup —
MyEnum(value)orMyEnum['NAME'] - Validation — check if a value exists with try/except
Quick Check: What two properties does every enum member have? (Answer: name and value)
Auto Values
Automatically Assigning Values
If you don't care about the actual values, you can use auto() to automatically assign them.
# Auto Values in Enums
print("=" * 50)
print("AUTO VALUES IN ENUMS")
print("=" * 50)
from enum import Enum, auto
# ============================================================
# BASIC AUTO VALUES
# ============================================================
print("\n1. BASIC AUTO VALUES")
class Color(Enum):
RED = auto()
GREEN = auto()
BLUE = auto()
YELLOW = auto()
print(" Auto values:")
for color in Color:
print(f" {color.name} = {color.value}")
# The values are automatically assigned: 1, 2, 3, 4
# ============================================================
# AUTO WITH STRING VALUES
# ============================================================
print("\n2. AUTO WITH STRING VALUES")
class Permission(Enum):
READ = "read"
WRITE = "write"
EXECUTE = "execute"
print(" String values:")
for perm in Permission:
print(f" {perm.name} = '{perm.value}'")
# You can also use auto() with strings:
# class AutoString(Enum):
# READ = auto() # This would be 1, not "read"
# ============================================================
# STARTING AUTO FROM A DIFFERENT NUMBER
# ============================================================
print("\n3. STARTING AUTO FROM A DIFFERENT NUMBER")
from enum import Enum, auto
class StatusCode(Enum):
def _generate_next_value_(name, start, count, last_values):
# Start from 100 instead of 1
return count + 100
OK = auto()
CREATED = auto()
ACCEPTED = auto()
BAD_REQUEST = auto()
print(" Status codes (starting from 100):")
for code in StatusCode:
print(f" {code.name} = {code.value}")
# ============================================================
# AUTO WITH CUSTOM START VALUE
# ============================================================
print("\n4. AUTO WITH CUSTOM START VALUE")
class Priority(Enum):
def _generate_next_value_(name, start, count, last_values):
# Start from 0 with step 5
return count * 5 + 5
LOW = auto()
MEDIUM = auto()
HIGH = auto()
URGENT = auto()
print(" Priority values (starting at 5, step 5):")
for p in Priority:
print(f" {p.name} = {p.value}")
# ============================================================
# AUTO VALUES WITH MIXED TYPES
# ============================================================
print("\n5. AUTO VALUES WITH MIXED TYPES")
class MixedEnum(Enum):
FIRST = auto() # int: 1
SECOND = "two" # string
THIRD = auto() # int: 2
FOURTH = 4.0 # float
print(" Mixed enum values:")
for member in MixedEnum:
print(f" {member.name} = {member.value} (type: {type(member.value).__name__})")
# ============================================================
# WHEN TO USE AUTO
# ============================================================
print("\n6. WHEN TO USE AUTO")
print(" Use auto() when:")
print(" - You don't care about the specific values")
print(" - You just need unique identifiers")
print(" - You want to keep the code clean")
print(" Don't use auto() when:")
print(" - The values have meaning (like status codes)")
print(" - You need to match external data")
print(" - You need specific numbers or strings")
Auto values key points:
- auto() — automatically assigns values
- Default — starts from 1 and increments
- Custom — define
_generate_next_value_for custom behavior - Mix types — you can mix auto() with explicit values
- When to use — when values don't matter, just uniqueness
Quick Check: What does auto() do in an Enum? (Answer: It automatically assigns a unique value to each member)
Enum Methods
Adding Methods to Enums
You can add methods to Enums, making them even more powerful. This is useful for adding behavior to your constants.
# Enum Methods
print("=" * 50)
print("ENUM METHODS")
print("=" * 50)
from enum import Enum
# ============================================================
# SIMPLE METHODS
# ============================================================
print("\n1. SIMPLE METHODS")
class Status(Enum):
PENDING = "pending"
PROCESSING = "processing"
COMPLETED = "completed"
FAILED = "failed"
def is_done(self):
"""Check if the status is final"""
return self in (Status.COMPLETED, Status.FAILED)
def get_description(self):
"""Get a description of the status"""
descriptions = {
Status.PENDING: "Waiting to start",
Status.PROCESSING: "Currently working",
Status.COMPLETED: "All done",
Status.FAILED: "Something went wrong"
}
return descriptions.get(self, "Unknown status")
status = Status.COMPLETED
print(f" Status: {status.name}")
print(f" Is done: {status.is_done()}")
print(f" Description: {status.get_description()}")
status = Status.PENDING
print(f" Status: {status.name}")
print(f" Is done: {status.is_done()}")
print(f" Description: {status.get_description()}")
# ============================================================
# ENUM WITH PROPERTIES
# ============================================================
print("\n2. ENUM WITH PROPERTIES")
class Size(Enum):
SMALL = ("S", 10)
MEDIUM = ("M", 20)
LARGE = ("L", 30)
XL = ("XL", 40)
def __init__(self, code, value):
self.code = code
self.value = value
@property
def display_name(self):
return f"{self.code} (${self.value})"
for size in Size:
print(f" {size.name}: {size.display_name}")
# ============================================================
# ENUM WITH CLASS METHODS
# ============================================================
print("\n3. ENUM WITH CLASS METHODS")
class Fruit(Enum):
APPLE = "apple"
BANANA = "banana"
ORANGE = "orange"
MANGO = "mango"
@classmethod
def list_all(cls):
"""Get all enum names"""
return [member.name for member in cls]
@classmethod
def get_by_value(cls, value):
"""Get enum member by value"""
try:
return cls(value)
except ValueError:
return None
print(f" All fruits: {Fruit.list_all()}")
print(f" Get by value 'apple': {Fruit.get_by_value('apple')}")
print(f" Get by value 'grape': {Fruit.get_by_value('grape')}")
# ============================================================
# ENUM WITH STATIC METHODS
# ============================================================
print("\n4. ENUM WITH STATIC METHODS")
class Color(Enum):
RED = "#FF0000"
GREEN = "#00FF00"
BLUE = "#0000FF"
YELLOW = "#FFFF00"
@staticmethod
def get_hex(color_name):
"""Get hex value by color name"""
try:
return Color[color_name.upper()].value
except KeyError:
return None
print(f" RED hex: {Color.RED.value}")
print(f" GREEN hex: {Color.GREEN.value}")
print(f" get_hex('blue'): {Color.get_hex('blue')}")
print(f" get_hex('purple'): {Color.get_hex('purple')}")
# ============================================================
# ENUM WITH COMPLEX BEHAVIOR
# ============================================================
print("\n5. ENUM WITH COMPLEX BEHAVIOR")
class LogLevel(Enum):
DEBUG = 10
INFO = 20
WARNING = 30
ERROR = 40
CRITICAL = 50
def should_log(self, level):
"""Check if this level should be logged"""
return self.value >= level.value
def get_color(self):
"""Get color for this log level"""
colors = {
LogLevel.DEBUG: "gray",
LogLevel.INFO: "blue",
LogLevel.WARNING: "yellow",
LogLevel.ERROR: "red",
LogLevel.CRITICAL: "darkred"
}
return colors.get(self, "white")
# Set current log level
current_level = LogLevel.WARNING
print(f" Current level: {current_level.name}")
for level in LogLevel:
if level.should_log(current_level):
print(f" {level.name}: {level.get_color()}")
Enum methods key points:
- Instance methods — add behavior to enum members
- Properties — computed values based on enum data
- Class methods — operations on the enum as a whole
- Static methods — utility functions related to the enum
- Complex behavior — enums can contain logic
Quick Check: Can you add methods to an Enum? (Answer: Yes, you can add instance methods, class methods, static methods, and properties)
Real-World Example
Building an Order Management System
# Real-World Example: Order Management System
from enum import Enum
from datetime import datetime
import uuid
print("=" * 60)
print("ORDER MANAGEMENT SYSTEM")
print("=" * 60)
# ============================================================
# ENUMS FOR THE SYSTEM
# ============================================================
class OrderStatus(Enum):
PENDING = "pending"
PROCESSING = "processing"
SHIPPED = "shipped"
DELIVERED = "delivered"
CANCELLED = "cancelled"
RETURNED = "returned"
def can_cancel(self):
"""Check if order can be cancelled"""
return self in (OrderStatus.PENDING, OrderStatus.PROCESSING)
def is_active(self):
"""Check if order is active"""
return self not in (OrderStatus.DELIVERED, OrderStatus.CANCELLED, OrderStatus.RETURNED)
class PaymentMethod(Enum):
CREDIT_CARD = "credit_card"
DEBIT_CARD = "debit_card"
PAYPAL = "paypal"
BANK_TRANSFER = "bank_transfer"
CRYPTO = "crypto"
def is_online(self):
return self in (PaymentMethod.CREDIT_CARD, PaymentMethod.DEBIT_CARD, PaymentMethod.PAYPAL)
class ShippingMethod(Enum):
STANDARD = "standard"
EXPRESS = "express"
SAME_DAY = "same_day"
INTERNATIONAL = "international"
def get_delivery_time(self):
times = {
ShippingMethod.STANDARD: "3-5 days",
ShippingMethod.EXPRESS: "1-2 days",
ShippingMethod.SAME_DAY: "Today",
ShippingMethod.INTERNATIONAL: "7-14 days"
}
return times.get(self, "Unknown")
# ============================================================
# ORDER CLASS USING ENUMS
# ============================================================
class Order:
def __init__(self, customer, items, payment_method, shipping_method):
self.order_id = str(uuid.uuid4())[:8]
self.customer = customer
self.items = items
self.payment_method = payment_method
self.shipping_method = shipping_method
self.status = OrderStatus.PENDING
self.created_at = datetime.now()
self.updated_at = datetime.now()
def process(self):
"""Process the order"""
if self.status != OrderStatus.PENDING:
return f"Order {self.order_id} cannot be processed (status: {self.status.name})"
# Check payment
if self.payment_method.is_online():
print(f" Processing online payment: {self.payment_method.value}")
else:
print(f" Processing offline payment: {self.payment_method.value}")
self.status = OrderStatus.PROCESSING
self.updated_at = datetime.now()
return f"Order {self.order_id} is now processing"
def ship(self):
"""Ship the order"""
if self.status != OrderStatus.PROCESSING:
return f"Order {self.order_id} cannot be shipped (status: {self.status.name})"
print(f" Shipping method: {self.shipping_method.value}")
print(f" Delivery time: {self.shipping_method.get_delivery_time()}")
self.status = OrderStatus.SHIPPED
self.updated_at = datetime.now()
return f"Order {self.order_id} has been shipped"
def deliver(self):
"""Deliver the order"""
if self.status != OrderStatus.SHIPPED:
return f"Order {self.order_id} cannot be delivered (status: {self.status.name})"
self.status = OrderStatus.DELIVERED
self.updated_at = datetime.now()
return f"Order {self.order_id} has been delivered"
def cancel(self):
"""Cancel the order"""
if not self.status.can_cancel():
return f"Order {self.order_id} cannot be cancelled (status: {self.status.name})"
self.status = OrderStatus.CANCELLED
self.updated_at = datetime.now()
return f"Order {self.order_id} has been cancelled"
def get_summary(self):
"""Get order summary"""
return {
"order_id": self.order_id,
"customer": self.customer,
"items": len(self.items),
"status": self.status.name,
"status_value": self.status.value,
"payment": self.payment_method.value,
"shipping": self.shipping_method.value,
"created": self.created_at.strftime("%Y-%m-%d %H:%M"),
"is_active": self.status.is_active()
}
# ============================================================
# DEMONSTRATION
# ============================================================
print("\n1. CREATING AN ORDER")
order = Order(
customer="Alice Johnson",
items=["Laptop", "Mouse", "Keyboard"],
payment_method=PaymentMethod.CREDIT_CARD,
shipping_method=ShippingMethod.EXPRESS
)
print(f" Order created: {order.order_id}")
print(f" Customer: {order.customer}")
print(f" Items: {order.items}")
print(f" Payment: {order.payment_method.value}")
print(f" Shipping: {order.shipping_method.value}")
print("\n2. ORDER PROCESSING")
print(f" {order.process()}")
print(f" Status: {order.status.name}")
print("\n3. SHIPPING")
print(f" {order.ship()}")
print(f" Status: {order.status.name}")
print("\n4. DELIVERY")
print(f" {order.deliver()}")
print(f" Status: {order.status.name}")
print("\n5. ORDER SUMMARY")
summary = order.get_summary()
for key, value in summary.items():
print(f" {key}: {value}")
print("\n6. TRYING TO CANCEL")
print(f" {order.cancel()}")
print("\n7. STATUS METHODS")
print(f" Can cancel? {order.status.can_cancel()}")
print(f" Is active? {order.status.is_active()}")
print("\n" + "=" * 60)
print("KEY TAKEAWAYS:")
print("=" * 60)
print("""
- Enums make status values clear and predictable
- Adding methods to enums keeps logic with the data
- Enums prevent invalid status values
- Type checking catches errors early
- Code is more readable and maintainable
""")
Real-world example key points:
- OrderStatus — defines all possible states with methods
- PaymentMethod — payment types with related logic
- ShippingMethod — shipping options with delivery times
- Enums with methods — behavior is attached to constants
- Prevents errors — only valid statuses can be used
Quick Check: Why are Enums better than strings for order status? (Answer: They prevent invalid statuses and can have associated behavior)
Best Practices
Using Enums Effectively
# Best Practices for Enums
print("=" * 60)
print("BEST PRACTICES FOR ENUMS")
print("=" * 60)
from enum import Enum, auto
# ============================================================
# 1. USE UPPERCASE FOR ENUM NAMES
# ============================================================
print("\n1. USE UPPERCASE FOR ENUM NAMES")
# Good - uppercase names
class Color(Enum):
RED = 1
GREEN = 2
BLUE = 3
# Also good - uppercase values
class Status(Enum):
PENDING = "PENDING"
PROCESSING = "PROCESSING"
COMPLETED = "COMPLETED"
print(" Enum names should be uppercase like constants")
# ============================================================
# 2. USE MEANINGFUL NAMES
# ============================================================
print("\n2. USE MEANINGFUL NAMES")
# Good - clear names
class UserRole(Enum):
ADMIN = "admin"
MANAGER = "manager"
EMPLOYEE = "employee"
GUEST = "guest"
# Bad - unclear names
class R(Enum):
A = 1
B = 2
C = 3
print(" Enum names should clearly describe what they represent")
# ============================================================
# 3. USE AUTO() FOR UNIQUE VALUES
# ============================================================
print("\n3. USE AUTO() FOR UNIQUE VALUES")
# Good - when values don't matter
class Priority(Enum):
LOW = auto()
MEDIUM = auto()
HIGH = auto()
# Also good - when values matter
class HttpStatus(Enum):
OK = 200
NOT_FOUND = 404
SERVER_ERROR = 500
print(" Use auto() when values don't matter, explicit when they do")
# ============================================================
# 4. ADD METHODS FOR BEHAVIOR
# ============================================================
print("\n4. ADD METHODS FOR BEHAVIOR")
class TaskStatus(Enum):
TODO = "todo"
IN_PROGRESS = "in_progress"
DONE = "done"
ARCHIVED = "archived"
def is_finished(self):
return self in (TaskStatus.DONE, TaskStatus.ARCHIVED)
def get_color(self):
colors = {
TaskStatus.TODO: "blue",
TaskStatus.IN_PROGRESS: "yellow",
TaskStatus.DONE: "green",
TaskStatus.ARCHIVED: "gray"
}
return colors.get(self, "white")
print(" Adding methods makes enums more powerful")
# ============================================================
# 5. USE ENUMS IN TYPE HINTS
# ============================================================
print("\n5. USE ENUMS IN TYPE HINTS")
from typing import List
def process_tasks(tasks: List[str], status: TaskStatus) -> List[str]:
"""Process tasks with a given status"""
return [task for task in tasks if status.is_finished()]
tasks = ["Task 1", "Task 2", "Task 3"]
result = process_tasks(tasks, TaskStatus.DONE)
print(f" Result: {result}")
# ============================================================
# 6. DON'T COMPARE ENUMS WITH STRINGS
# ============================================================
print("\n6. DON'T COMPARE ENUMS WITH STRINGS")
class Size(Enum):
SMALL = "small"
MEDIUM = "medium"
LARGE = "large"
size = Size.MEDIUM
# Bad - comparing with string
if size.value == "medium":
print(" This works but is error-prone")
# Good - comparing with enum
if size == Size.MEDIUM:
print(" This is the correct way")
print(" Always compare enum members, not their values")
# ============================================================
# 7. SUMMARY
# ============================================================
print("\n" + "=" * 60)
print("BEST PRACTICES SUMMARY")
print("=" * 60)
print("""
- Use uppercase names for enum members
- Use meaningful, clear names
- Use auto() when values don't matter
- Add methods for behavior
- Use enums in type hints
- Compare enum members, not values
- Keep enums focused on one thing
- Document what each enum represents
""")
Best practices summary:
- Use uppercase — enum members should be uppercase
- Meaningful names — clearly describe what they represent
- Use auto() — when values don't matter
- Add methods — attach behavior to enums
- Use in type hints — for better type safety
- Compare members — not values
Quick Check: Should you compare an enum member to a string? (Answer: No — compare enum members directly)
Try It Yourself
Experiment with Enums in the editor below.
ENUMS - PRACTICE
==================================================
1. BASIC ENUM
Today: MONDAY (value: 1)
MONDAY: 1
TUESDAY: 2
WEDNESDAY: 3
THURSDAY: 4
FRIDAY: 5
SATURDAY: 6
SUNDAY: 7
2. ENUM WITH AUTO VALUES
Roles:
ADMIN: 1
USER: 2
GUEST: 3
MODERATOR: 4
3. ENUM WITH METHODS
Weather: RAINY
Is cold: True
Icon: 🌧️
4. USING ENUMS WITH DICTIONARIES
PENDING: yellow
APPROVED: green
REJECTED: red
You've Got It!
You now understand Enums in Python. You know how to create them, use them, and add methods to make them more powerful.
Quick Quiz
Test what you've learned:
Frequently Asked Questions
What is an Enum in Python?
When should I use an Enum?
Can I compare Enums with strings?
enum.value == "string", but this is not recommended. It's better to compare enum members directly: enum == MyEnum.MEMBER.
What is auto() in Enums?
auto() automatically assigns a unique value to each enum member. By default, it assigns 1, 2, 3, etc. You can customize this by defining _generate_next_value_.
Can I add methods to an Enum?
How do I iterate over all enum members?
for member in MyEnum: or get a list of all members with list(MyEnum).
Where to Go From Here
Now that you understand Enums in Python, check out these related topics:
Dataclasses
Learn how dataclasses work with Enums.
Learn More →Type Hints
Learn how to use Enums with type hints.
Learn More →__slots__
Learn how __slots__ works with Enums.
Learn More →