Python Enum to String without Class Name
When using Python Enums, the default string output includes the class name (e.g., <MyEnum.MEMBER: 'value'>), which is often unsuitable for clean logging, API responses, or direct printing. This article demonstrates how to leverage Python's dunder methods (__str__, __repr__, __format__) to gain complete control over the string representation of your Enum members.
The Default Problem Statement
By default, an Enum member prints its full, verbose representation, including the class name and the member name, which is usually not what's desired when serializing to a simple string.
from enum import Enum
class Color(Enum):
RED = 'red'
GREEN = 'green'
my_color = Color.RED
# Default print output:
# print(my_color) # Output: Color.RED
# print(str(my_color)) # Output: Color.RED
Solution 1: Controlling Standard String Output with __str__
The __str__ method controls the output when an object is converted to a string using str() or when it is printed via the print() function. Overriding this method is the primary way to remove the class name from basic output.
class OutputMode(Enum):
COMPACT = 1
VERBOSE = 2
# Override __str__ to return only the member's value or name
def __str__(self):
# Recommended: return the raw value, which is useful for APIs
return str(self.value)
# Usage:
mode = OutputMode.COMPACT
print(f"Current mode value: {mode}") # Calls __str__ implicitly
print(str(mode))
# Output: 1
# Output: 1
class RoleNameOnly(Enum):
ADMIN = 'admin'
def __str__(self):
# Alternative: return the member's name (ALL_CAPS)
return self.name
Solution 2: Controlling Debug and List Output with __repr__
While __str__ controls the friendly output, __repr__ controls the official string representation used for debugging, logging collections (like lists and dictionaries), and interactive shell output. Experts often leave __repr__ verbose for debugging but may override it for specific needs.
class DebugStatus(Enum):
ACTIVE = 1
INACTIVE = 0
def __str__(self):
return self.name.lower() # Friendly output
# Override __repr__ for clean list display
def __repr__(self):
# Return a clean, non-class-prefixed string representation
return f"'{self.name}'"
# Usage:
statuses = [DebugStatus.ACTIVE, DebugStatus.INACTIVE]
print(f"String output: {statuses[0]}")
# Output: active (Calls __str__)
print(f"List representation: {statuses}")
# Output: ['ACTIVE', 'INACTIVE'] (Calls __repr__ for each element)
Solution 3: Custom Formatting in f-strings with __format__
The __format__ method allows you to define specialized formatting based on a format specifier provided in an f-string (e.g., {member:spec}). This is highly advanced and useful for converting Enum values into hex, binary, or lowercase on the fly.
class ConfigFlag(Enum):
READ = 1
WRITE = 2
EXECUTE = 4
def __format__(self, format_spec):
if format_spec == 'hex':
# Format the raw value as hexadecimal
return f"0x{self.value:X}"
elif format_spec == 'lower':
# Format the member name in lowercase
return self.name.lower()
# Fallback to default formatting if specifier is not handled
return super().__format__(format_spec)
# Usage:
flag = ConfigFlag.EXECUTE
print(f"Hex output: {flag:hex}")
# Output: 0x4
print(f"Lowercase output: {flag:lower}")
# Output: execute
Solution 4: Injecting __str__ via Mixins
To avoid repeating the boilerplate __str__ implementation across multiple Enum classes, you can use a simple mixin that provides the desired behavior.
class ValueStrMixin:
"""Mixin to ensure __str__ always returns the raw value."""
def __str__(self):
return str(self.value)
class SimpleStatus(ValueStrMixin, Enum):
ON = "active"
OFF = "inactive"
class ErrorCode(ValueStrMixin, Enum):
MISSING_PARAM = 400
ACCESS_DENIED = 403
# Usage:
print(f"Status output: {SimpleStatus.ON}")
# Output: active
print(f"Error output: {ErrorCode.ACCESS_DENIED}")
# Output: 403
# Annotation: When SimpleStatus is instantiated, it inherits __str__ from
# ValueStrMixin, ensuring consistent formatting across all inheriting Enums.
