Skip to content

Enum Methods and Customization

Add methods to enums and customize their behavior to create powerful, expressive types.


Adding Methods to Enums

from enum import Enum

class Size(Enum):
    SMALL = 1
    MEDIUM = 2
    LARGE = 3
    XLARGE = 4

    def get_next_size(self):
        '''Get the next larger size'''
        members = list(Size)
        idx = members.index(self)
        if idx < len(members) - 1:
            return members[idx + 1]
        return self

    def get_price_multiplier(self):
        '''Get price multiplier for this size'''
        multipliers = {
            Size.SMALL: 1.0,
            Size.MEDIUM: 1.25,
            Size.LARGE: 1.5,
            Size.XLARGE: 1.75
        }
        return multipliers[self]

small = Size.SMALL
print(small.get_next_size())        # Size.MEDIUM
print(small.get_price_multiplier()) # 1.0

Properties in Enums

from enum import Enum
from functools import cached_property

class UserRole(Enum):
    GUEST = "guest"
    USER = "user"
    MODERATOR = "moderator"
    ADMIN = "admin"

    @property
    def can_delete_posts(self):
        '''Check if role can delete posts'''
        return self in (UserRole.MODERATOR, UserRole.ADMIN)

    @property
    def can_ban_users(self):
        '''Check if role can ban users'''
        return self == UserRole.ADMIN

    @property
    def display_name(self):
        '''Human-readable role name'''
        return self.value.capitalize()

role = UserRole.MODERATOR
print(f"Role: {role.display_name}")          # Role: Moderator
print(f"Can delete posts: {role.can_delete_posts}")  # True
print(f"Can ban users: {role.can_ban_users}")        # False

Class Methods in Enums

from enum import Enum

class Environment(Enum):
    DEVELOPMENT = "development"
    STAGING = "staging"
    PRODUCTION = "production"

    @classmethod
    def from_string(cls, value: str):
        '''Create from string, case-insensitive'''
        for member in cls:
            if member.value.lower() == value.lower():
                return member
        raise ValueError(f"Unknown environment: {value}")

    @classmethod
    def is_production(cls, env):
        '''Check if environment is production'''
        return env == cls.PRODUCTION

env = Environment.from_string("PRODUCTION")
print(env)                                  # Environment.PRODUCTION
print(Environment.is_production(env))       # True

Custom Enum with str

from enum import Enum

class Status(Enum):
    PENDING = "pending"
    RUNNING = "running"
    COMPLETED = "completed"
    FAILED = "failed"

    def __str__(self):
        '''Custom string representation'''
        symbols = {
            Status.PENDING: "⏳",
            Status.RUNNING: "▶️",
            Status.COMPLETED: "✅",
            Status.FAILED: "❌"
        }
        return f"{symbols[self]} {self.value}"

status = Status.RUNNING
print(status)           # ▶️ running
print(str(status))      # ▶️ running

Enum with repr

from enum import Enum

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

    def __repr__(self):
        '''Detailed representation'''
        return f"<Priority: {self.name} (level {self.value})>"

priority = Priority.HIGH
print(repr(priority))   # <Priority: HIGH (level 3)>

Computed Enum Values

from enum import Enum
from datetime import datetime

class LogLevel(Enum):
    DEBUG = (1, "DEBUG", "🔍")
    INFO = (2, "INFO", "ℹ️")
    WARNING = (3, "WARNING", "⚠️")
    ERROR = (4, "ERROR", "❌")
    CRITICAL = (5, "CRITICAL", "🔴")

    def __init__(self, level, name_str, symbol):
        self.level = level
        self.name_str = name_str
        self.symbol = symbol

    def format_message(self, message: str) -> str:
        '''Format log message'''
        timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
        return f"[{timestamp}] {self.symbol} {self.name_str}: {message}"

log = LogLevel.ERROR
print(log.format_message("Database connection failed"))

Customizing Lookup

from enum import Enum

class ErrorCode(Enum):
    NOT_FOUND = 404
    FORBIDDEN = 403
    SERVER_ERROR = 500

    def __init__(self, code):
        self.code = code

    @classmethod
    def from_http_status(cls, status_code: int):
        '''Look up by HTTP status code'''
        for member in cls:
            if member.code == status_code:
                return member
        raise ValueError(f"No enum for status code: {status_code}")

    def get_message(self) -> str:
        '''Get friendly error message'''
        messages = {
            404: "Resource not found",
            403: "Access forbidden",
            500: "Internal server error"
        }
        return messages.get(self.code, "Unknown error")

error = ErrorCode.from_http_status(404)
print(f"{error.code}: {error.get_message()}")  # 404: Resource not found

When to Add Methods

  • Validation logic
  • Conversion operations
  • Related computations
  • Display formatting
  • Lookup functionality