|$ curl https://forge-ai.dev/api/markdown?path=docs/python/abc-enums
$cat docs/abc-&-enums.md
updated Today·18-24 min read·published

ABC & Enums

PythonABCEnumIntermediate🎯Free Tools
Introduction

abc defines abstract base classes; enum defines enumerations. Together they make illegal states harder to represent.

ABC & abstractmethod
abc_demo.py
Python
1from abc import ABC, abstractmethod
2
3class Repository(ABC):
4 @abstractmethod
5 def get(self, id: int) -> dict: ...
6
7 @abstractmethod
8 def save(self, row: dict) -> None: ...
9
10 def get_or_default(self, id: int, default: dict | None = None) -> dict | None:
11 try:
12 return self.get(id)
13 except KeyError:
14 return default
15
16class MemoryRepo(Repository):
17 def __init__(self) -> None:
18 self._data: dict[int, dict] = {}
19 def get(self, id: int) -> dict:
20 return self._data[id]
21 def save(self, row: dict) -> None:
22 self._data[int(row["id"])] = row
23
24# Repository() # TypeError: abstract
25repo = MemoryRepo()
26repo.save({"id": 1, "name": "Ada"})
27print(repo.get(1))
Abstract Properties
abs_prop.py
Python
1from abc import ABC, abstractmethod
2
3class Shape(ABC):
4 @property
5 @abstractmethod
6 def area(self) -> float: ...
7
8class Rect(Shape):
9 def __init__(self, w: float, h: float):
10 self.w, self.h = w, h
11 @property
12 def area(self) -> float:
13 return self.w * self.h
14
15print(Rect(3, 4).area)
Enum Basics
enum_basics.py
Python
1from enum import Enum, auto
2
3class Color(Enum):
4 RED = auto()
5 GREEN = auto()
6 BLUE = auto()
7
8print(Color.RED, Color.RED.name, Color.RED.value)
9print(Color["RED"], Color(1))
10for c in Color:
11 print(c)
StrEnum & IntEnum
strenum.py
Python
1from enum import StrEnum, IntEnum, auto
2
3class Status(StrEnum):
4 OK = "ok"
5 ERROR = "error"
6 PENDING = "pending"
7
8assert Status.OK == "ok" # StrEnum mixes with str
9print(f"status={Status.OK}")
10
11class ExitCode(IntEnum):
12 SUCCESS = 0
13 USAGE = 2
14 FAILURE = 1
15
16raise SystemExit(ExitCode.USAGE)

info

Prefer StrEnum for JSON/API string unions; IntEnum for numeric codes.
Flag & IntFlag
flag.py
Python
1from enum import Flag, auto
2
3class Perm(Flag):
4 READ = auto()
5 WRITE = auto()
6 EXEC = auto()
7
8rw = Perm.READ | Perm.WRITE
9print(Perm.READ in rw)
10print(rw & Perm.WRITE)
11print(list(rw))
unique & Aliases
unique.py
Python
1from enum import Enum, unique
2
3@unique
4class Direction(Enum):
5 N = "n"
6 S = "s"
7 E = "e"
8 W = "w"
9 # NORTH = "n" # would fail @unique as alias
10
11class Color(Enum):
12 RED = 1
13 CRIMSON = 1 # alias of RED
14print(Color.CRIMSON is Color.RED)
Functional API
functional_enum.py
Python
1from enum import Enum
2
3Animal = Enum("Animal", ["ANT", "BEE", "CAT"])
4print(Animal.ANT, list(Animal))
collections.abc

For typing and isinstance checks against collection protocols, use collections.abc — Sequence, Mapping, Iterable, Callable, etc.

coll_abc.py
Python
1from collections.abc import Sequence, Mapping
2
3def first(xs: Sequence[int]) -> int:
4 return xs[0]
5
6def keys(m: Mapping[str, int]) -> list[str]:
7 return list(m)
Patterns
GoalTool
Force subclass implementationABC + abstractmethod
Closed set of string valuesStrEnum
Bitset optionsFlag
JSON-friendly statusStrEnum
Plugin interfaceABC
ABC Meta register
register.py
Python
1from abc import ABC
2from collections.abc import Sequence
3
4class MySeq(ABC):
5 pass
6
7MySeq.register(tuple)
8assert issubclass(tuple, MySeq)
9assert isinstance((1, 2), MySeq)
10
11# Virtual subclass — no inheritance required
12# Useful for adapting third-party types to your ABC checks
Methods on Enums
enum_methods.py
Python
1from enum import StrEnum
2
3class Priority(StrEnum):
4 LOW = "low"
5 MEDIUM = "medium"
6 HIGH = "high"
7
8 def weight(self) -> int:
9 return {Priority.LOW: 1, Priority.MEDIUM: 2, Priority.HIGH: 3}[self]
10
11print(Priority.HIGH.weight())
12print(sorted(Priority, key=lambda p: p.weight()))
Enums with match
match_enum.py
Python
1from enum import StrEnum
2
3class Op(StrEnum):
4 ADD = "add"
5 MUL = "mul"
6
7def apply(op: Op, a: int, b: int) -> int:
8 match op:
9 case Op.ADD:
10 return a + b
11 case Op.MUL:
12 return a * b
13
14print(apply(Op.ADD, 2, 3))
Pitfalls
  • Forgetting to implement all abstract methods
  • Using Enum mutable values (lists) — avoid
  • Comparing Enum with bare strings without StrEnum
  • Overusing Flag when a set[str] would be clearer
IntFlag
intflag.py
Python
1from enum import IntFlag, auto
2
3class Style(IntFlag):
4 BOLD = auto()
5 ITALIC = auto()
6 UNDERLINE = auto()
7
8s = Style.BOLD | Style.ITALIC
9print(int(s), Style.BOLD in s)
10print(s & ~Style.ITALIC)
Typing Notes

Annotate with the Enum type itself: status: Status. For StrEnum, APIs can accept str and validate into the enum via constructors or Pydantic.

typing_enum.py
Python
1from enum import StrEnum
2
3class Status(StrEnum):
4 OK = "ok"
5 ERR = "error"
6
7def handle(status: Status) -> str:
8 return f"handled {status}"
9
10print(handle(Status("ok")))
Summary

Use ABCs to define implementable contracts; use Enum/StrEnum/Flag for closed value sets. Prefer StrEnum at stringly-typed boundaries and keep enum values immutable.

Checklist
  • All abstract methods implemented before instantiation
  • StrEnum for JSON string unions
  • @unique when aliases are bugs
  • Keep enum members immutable constants
  • Prefer ABC over NotImplementedError stubs for public APIs
$Blueprint — Engineering Documentation·Section ID: PYTHON-ABC-ENUM·Revision: 1.0

Community

Get help on Slack, Discord or VIP

Stuck on a guide? Join the community and ask.