Python

P
PythonHub
Progress 0%

Python

  • Home
  • History of Python
  • Applications of Python
  • Introduction To Python
    • What is Python
    • Character Set
    • Tokens in Python
    • Python Execution Mode
    • Variable And Identifiers
    • Data Types in Python
    • Operators And Expressions
    • Constants in Python
    • Assignment Statement
    • Input / Output in Python
    • Simple Python Scripts
    • Namespace in Python
    • 📝 Assignments
  • Operators in Python
    • Arithmetic Operators
    • Assignment Operators
    • Shorthand Assignment Operators
    • Relational Operators
    • Logical Operators
    • Bitwise Operators
    • Special Operators
    • 📝 Assignments
  • Input Output in Python
    • Accept Input
    • Output Formatting
    • 📝 Assignments
  • Conditional Statement
    • Decision Making
    • if Statement
    • IF-ELSE STATEMENT
    • IF-ELSE LADDER
    • NESTED IF-ELSE
    • Short Hand IF-ELSE
    • 📝 Assignments
  • Loops
    • Introduction to Loops
    • While Loop
    • Nested While Loop
    • 📝 While Loop Assignments
    • For Loop
    • For Loop Examples
    • Nested For Loop
    • Nested For Loop Examples
    • Infinite While Loops
    • Infinite For Loops
    • Break, Continue and Else in Loops
    • Difference Between For and While Loop
    • For Each Loop
    • 📝 For Each Assignments
    • 📝 All Loops Assignments
  • List
    • List in Python
    • Access List Elements
    • List Functions
    • Iterate (Loop) List
    • List Comprehension
    • 📝 Assignments
  • Tuple
    • Tuple in Python
    • Access Tuple Elements
    • Tuple Functions
    • Iterate (Loop) Tuple
    • Unpack Tuple
    • Tuple Comprehension
    • 📝 Assignments
  • Set
    • Set in Python
    • Access Set Elements
    • Set Methods
    • Iterate (Loop) Set
    • Pack/Unpack Set
    • Set Comprehension
    • 📝 Assignments
  • Dictionary
    • Dictionary
    • Access Dictionary Items
    • Dictionary Methods
    • Iterate (Loop) Dictionary
    • Formatting Dictionaries
    • Nested Dictionaries
    • Dictionary Comprehension
    • 📝 Assignments
  • Diff List Tuple Set Dictionary
    • List vs Tuple
    • List vs Set
    • List vs Dictionary
    • Tuple vs Set
    • Tuple vs Dictionary
    • Dictionary vs Set
    • 📝 Assignments
  • Exception
    • Error vs Exception
    • Types of Exception
    • Exception Handling
    • User Defined Exception
    • Logging Exception
    • 📝 Assignments
  • Functions
    • Introduction to Functions
    • Modular Programming
    • Types of Functions
    • Inbuilt Functions
    • Need For User-Defined Function
    • Elements of User Defined Function
    • Function Arguments
    • Nesting of Functions
    • Recursion
    • Global Local and Non Local
    • Python Lambda Functions
    • 📝 Assignments
  • Python Module
    • Introduction to Module
    • Inbuilt Modules in Python
    • User Defined Module
    • 📝 Assignments
  • File Handling
    • Introduction to Files
    • Create File
    • Read Files
    • Write to File
    • Rename File
    • Copy File
    • Move File
    • List Files in Directory
    • Binary Files
    • Zipping and Unzipping Files
    • 📝 Assignments
  • Strings
    • Basics of Strings
    • String Special Operators
    • String Formatting Operators
    • String Methods
    • 📝 Assignments
  • Regular Expressions
  • Python OOPS
    • Basics of Object Oriented
    • What are Classes and Objects?
    • Creating Class and Object
    • OOP vs Procedural Programming
    • Difference Between Classes and Objects
    • Constructors
    • Destructor
    • Built Class Methods and Attributes
    • Class and Instance Variables
    • Inheritance in Python
    • Single Inheritance
    • Multiple Inheritance
    • Multilevel Inheritance
    • Hierarchical Inheritance
    • Hybrid Inheritance
    • Abstraction
    • Method Overriding
    • Abstract Method
    • Interfaces in Python
    • Abstract Class vs Interface
    • Public, Private and Protected
    • Overloading vs Overriding
    • Inheritance vs Composition
    • Encapsulation
    • Polymorphism
    • Inner Classes
    • 📝 Assignments
  • Advanced Python
    • Iterator in Python
    • Generator in Python
    • Decorator in Python
    • Type Hints in Python
    • Async/Await Programming
    • Dataclasses in Python
    • Context Managers in Python
    • Property Decorator in Python
    • __slots__ in Python
    • Enums in Python
    • Walrus Operator in Python
    • Match-Case in Python
    • 📝 Assignments
  • Python Standard Library
    • Collections Module
    • Itertools Module
    • Functools Module
    • Datetime Module
    • JSON Module
    • OS Module
    • Sys Module
    • Random Module
    • Math Module
    • 📝 Assignments
  • Python Testing
    • Unit Testing in Python
    • Pytest Framework
    • Mocking in Python
    • 📝 Assignments
  • Python Best Practices
    • PEP 8 Style Guide
    • Docstrings in Python
    • Logging in Python
    • Code Optimization Tips
    • Debugging Techniques
    • 📝 Assignments
  • MySQL Database in Python
    • Introduction to MySQL with Python
    • DBMS vs File System
    • Connecting to MySQL Database
    • Create Database in MySQL
    • Create Table in MySQL
    • Insert Data in MySQL
    • Insert Multiple Rows
    • Select Data from MySQL
    • WHERE Clause in MySQL
    • Update Data in MySQL
    • Delete Data from MySQL
    • Parameterized Queries
    • Transaction Management
    • Error Handling
    • Connection Pooling
    • MySQL Drivers Guide
    • Joins in MySQL
    • Aggregation Functions
    • Backup MySQL Database
    • Best Practices
    • 📝 Assignments
  • MySQL Database Operations
    • SELECT Statement
    • MySQL Operators
    • DDL Statements
    • DML Statements
    • Subqueries
    • JOIN Operations
    • Aggregation
    • Case Study
    • 📝 Assignments
  • Graphics in Python
  • Threads in Python
    • Introduction to Threads
    • Process vs Threads
    • Concurrent Programming & GIL
    • Uses of Threads
    • Creating Threads
    • Single Tasking
    • Multi Tasking
    • Thread Synchronization
    • 📝 Assignments
  • Interview Questions & Answers
  • Python Case Studies
  • Multiple Choice Questions
  • 📝 Practice Problems
Get in Touch
  • tech2dsm@gmail.com

© Sankalan Data Tech

Python Language Interactive Tutorial

Python: Enums

Python Enums - Complete Guide

Organize your constants and write cleaner code with Enums.

Created by Sankalan Data Tech Team Verified
Data Engineers, Analysts, Scientists & Trainers
Created by experienced Python developers, data engineers, and data scientists to make programming easy through practical examples, real-world experience, and clear explanations.
On this page:
  • What are Enums?
  • Why Use Enums?
  • Basic Usage
  • Enum Members
  • Auto Values
  • Enum Methods
  • Real-World Example
  • Best Practices
  • Try It Yourself
  • Quick Quiz
  • Frequently Asked Questions
Share this tutorial:
Twitter LinkedIn Facebook WhatsApp Reddit Telegram Email Copy Link
What You'll Learn Here
  • 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?

1

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

2

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 == or is
  • 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

3

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 == or is for members
  • Lookup — MyEnum(value) or MyEnum['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

4

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

5

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

6

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

7

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.

Loading Pyodide... 0%
Python Code Editor
==================================================
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:

1. What do you inherit from to create an Enum?
2. How do you access an enum member by its name?
3. What does auto() do in an Enum?
4. Can you add methods to an Enum?
5. Why should you use Enums instead of strings for constants?

Frequently Asked Questions

What is an Enum in Python? ▼

An Enum (enumeration) is a set of named constants. It's a way to define a fixed set of values that are related, like days of the week, status codes, or colors. Enums make code more readable and prevent errors.

When should I use an Enum? ▼

Use Enums when you have a fixed set of related constants. Examples include status values, configuration options, categories, types, and any situation where you'd use a limited set of strings or integers.

Can I compare Enums with strings? ▼

You can compare an enum's value to a string using 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? ▼

Yes! You can add instance methods, class methods, static methods, and properties to Enums. This allows you to attach behavior to your constants, making your code more organized and powerful.

How do I iterate over all enum members? ▼

You can iterate over an Enum using a for loop: 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 →
Interview Resources
  • Python Syntax & Variables Interview Questions
  • Top SQL Interview Questions & Answers
  • SQL Joins: Displaying Data from Multiple Tables FAQ
  • Python Lists and Dictionaries Interview Questions
  • Python OOP Interview Questions
  • SQL Set Operators Interview Questions
Previous: __slots__ Next: Walrus Operator →