Skip to content
  • Enums in Depth · Python

Enums in Depth

LearnViaNotes @learnvianotes· 4 min read

An Enum is a fixed set of named, unique constants. Members are singletons, are iterable in definition order, and make invalid states unrepresentable — no more magic strings and numbers.

Basics: names, values, lookup

Python
from enum import Enum

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

print(Color.RED, repr(Color.RED))            # Color.RED <Color.RED: 1>
print(Color(2), Color["BLUE"])               # Color.GREEN Color.BLUE
print(Color.RED.name, Color.RED.value)       # RED 1
print(len(Color), [c.name for c in Color])   # 3 ['RED', 'GREEN', 'BLUE']
print(Color.RED == 1, Color.RED is Color(1)) # False True
try:
    Color(7)
except ValueError as e:
    print(e)                                 # 7 is not a valid Color
You haveYou wantWrite
a value (e.g. from a DB)the memberColor(2)
a name (e.g. from config)the memberColor['GREEN']
a memberits name / valuem.name / m.value
the classall memberslist(Color) or Color.__members__

auto() and generated values

Python
from enum import Enum, auto

class Status(Enum):
    TODO = auto()
    DOING = auto()
    DONE = auto()

class Method(Enum):
    @staticmethod
    def _generate_next_value_(name, start, count, last_values):
        return name.lower()                # customise what auto() produces
    GET = auto()
    POST = auto()

print([s.value for s in Status])           # [1, 2, 3]
print(Method.POST.value)                   # post

Aliases and @unique

Python
from enum import Enum, unique

class Shape(Enum):
    SQUARE = 2
    CIRCLE = 3
    BOX = 2                                  # same value → an alias of SQUARE

print(Shape.BOX, Shape(2))                   # Shape.SQUARE Shape.SQUARE
print([s.name for s in Shape], list(Shape.__members__))   # ['SQUARE', 'CIRCLE'] ['SQUARE', 'CIRCLE', 'BOX']

try:
    @unique
    class Bad(Enum):
        A = 1
        B = 1
except ValueError as e:
    print(e)                                 # duplicate values found in <enum 'Bad'>: B -> A

IntEnum, StrEnum & Flag

Python
from enum import IntEnum, StrEnum, auto

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

class Env(StrEnum):                          # 3.11+
    DEV = auto()                             # StrEnum's auto() → the lower-cased name
    PROD = auto()

print(Priority.HIGH > Priority.LOW, Priority.HIGH + 1)   # True 4
print(sorted([3, Priority.LOW]))                         # [<Priority.LOW: 1>, 3]
print(Env.PROD, Env.PROD == "prod", Env.DEV.upper())     # prod True DEV
print(f"api-{Env.DEV}.example.com")                     # api-dev.example.com
Python
from enum import Flag, auto

class Perm(Flag):
    READ = auto()        # 1
    WRITE = auto()       # 2
    EXEC = auto()        # 4
    RW = READ | WRITE    # a named combination

p = Perm.READ | Perm.EXEC
print(p)                                         # Perm.READ|EXEC
print(Perm.READ in p, Perm.WRITE in p)           # True False
print(Perm.RW.value, [m.name for m in Perm.RW])  # 3 ['READ', 'WRITE']
print(p & ~Perm.EXEC, bool(Perm(0)))             # Perm.READ False
TypeMembers are also…Use when
Enumnothing elseDefault choice — strict, can't be mixed up with ints/strings
IntEnumintsInterop with code/protocols that expect integers (HTTP status, DB codes)
StrEnumstrsValues go into JSON, URLs, logs, config files
Flag / IntFlagbit flagsCombinable options: permissions, feature toggles

Methods, properties & data on members

Python
from enum import Enum

class Planet(Enum):
    MERCURY = (3.303e23, 2.4397e6)
    EARTH = (5.976e24, 6.37814e6)

    def __init__(self, mass, radius):       # the tuple value is unpacked into __init__
        self.mass, self.radius = mass, radius

    @property
    def gravity(self):
        return round(6.673e-11 * self.mass / self.radius ** 2, 2)

    @classmethod
    def heaviest(cls):
        return max(cls, key=lambda p: p.mass)

print(Planet.EARTH.gravity, Planet.heaviest().name)   # 9.8 EARTH

Enums in match & JSON

Python
import json
from enum import Enum, StrEnum

class Light(Enum):
    RED = "stop"
    YELLOW = "slow"
    GREEN = "go"

def action(light):
    match light:
        case Light.RED | Light.YELLOW:        # dotted names are value patterns
            return "brake"
        case Light.GREEN:
            return "drive"

print(action(Light.YELLOW), action(Light("go")))              # brake drive

class Role(StrEnum):
    ADMIN = "admin"

print(json.dumps({"role": Role.ADMIN}))                       # {"role": "admin"}
try:
    json.dumps({"light": Light.RED})
except TypeError:
    print("plain Enum is not JSON serializable")              # plain Enum is not JSON serializable
print(json.dumps({"light": Light.RED}, default=lambda e: e.value))   # {"light": "stop"}
print(Light(json.loads('{"light": "stop"}')["light"]))       # Light.RED

Interview angle

Why use an Enum instead of string or int constants?

How do you convert between an enum and its stored value?

What is an enum alias?

Free for students and teachers

Write notes like this one

Cards for every idea, quizzes and flashcards, read aloud — on the web and your phone.

Something wrong with this note? Open it to report