šŸš€ LEVEL UP TO SENIOR:Unlock 500+ Advanced Practical Challenges & Exercises.
šŸŽ“ COURSERA PARTNER:Earn professional Google, Meta, and IBM certificates to supercharge your resume.
HTML MASTER CLASS /// LEARN TAGS /// BUILD STRUCTURE /// SEMANTIC WEB /// HTML MASTER CLASS /// LEARN TAGS ///

Python Enums

Replace magic strings and loose integer constants with Python's enum module — type-safe, self-documenting, and IDE-autocompletable.

⚔ Total XP: 0|šŸ’» python XP: 0

Skill Matrix

UNLOCK NODES BY LEARNING NEW TAGS.

System Hub

Core logic.

Quick Quiz //

What is the idiomatic way to compare a status value against a known state?


šŸš€ LEVEL UP TO SENIOR:Unlock 500+ Advanced Practical Challenges & Exercises.
šŸŽ“ COURSERA PARTNER:Earn professional Google, Meta, and IBM certificates to supercharge your resume.

Every codebase eventually needs a closed set of named values — order statuses, log levels, directions. The enum module, in the standard library since 3.4 and steadily improved since, gives you a type-safe, autocomplete-friendly way to define them instead of scattering string literals or bare integers everywhere.

1Why Enums Beat Magic Strings and Loose Constants

Before enum, a closed set of states was usually represented as either raw string literals ("pending", "shipped") scattered across the codebase, or module-level integer constants (PENDING = 1). Both approaches share the same weakness: nothing stops you from passing an unrelated string or int where a status was expected, and a typo like "Pending" fails silently — it's just a different string, not an error, until some comparison mysteriously never matches.

class OrderStatus(Enum): groups related constants under one namespace, gives each a distinct identity (OrderStatus.PENDING is not equal to the string "pending" — it's an object with a .name and a .value), and makes every valid state discoverable via autocomplete the moment you type OrderStatus.. A static type checker treats a parameter annotated status: OrderStatus as accepting only genuine OrderStatus members, catching an accidental "pending" string argument as a type error before the code runs.

The idiomatic comparison is always against the member itself — status == OrderStatus.PENDING — never against the raw .value. Comparing against .value throws away exactly the type safety that motivated using an enum in the first place, since a raw string equality check has no way to catch a typo.

āœ•
—
+
from enum import Enum

class OrderStatus(Enum):
    PENDING = "pending"
    SHIPPED = "shipped"
    DELIVERED = "delivered"

status = OrderStatus.PENDING
print(status)          # OrderStatus.PENDING
print(status.value)    # 'pending'
print(status == OrderStatus.PENDING)  # True
localhost:3000
Console Output
OrderStatus.PENDING
Distinct identity, not just the string 'pending'

2StrEnum, IntEnum, and Interoperating With the Outside World

A plain Enum member is deliberately *not* equal to its underlying value by default (OrderStatus.PENDING != "pending"), which is exactly the safety property that makes typos loud instead of silent. But sometimes you genuinely need interoperability — serializing directly to JSON, or comparing against a raw string that came from an external API or a database column.

StrEnum (3.11+) and IntEnum solve that by making the enum class itself a subclass of str or int respectively: Role.ADMIN == "admin" is True for a StrEnum, and json.dumps() serializes a StrEnum member directly as its string value with no custom encoder needed. Before 3.11, the equivalent pattern was class Role(str, Enum):, which is still valid and necessary if you need to support older interpreters.

The trade-off is real: mixing in str or int reintroduces some of the looseness a plain Enum avoids — Role.ADMIN == "admin" now succeeds even from a typo-prone string literal that was never validated against the enum. Reach for StrEnum/IntEnum specifically at serialization or interop boundaries, and prefer a plain Enum internally wherever you control both sides of the comparison.

āœ•
—
+
from enum import StrEnum

class Role(StrEnum):
    ADMIN = "admin"
    EDITOR = "editor"

print(Role.ADMIN == "admin")   # True — StrEnum IS a str subclass
import json
print(json.dumps({"role": Role.ADMIN}))  # {"role": "admin"}
localhost:3000
JSON Serialization
json.dumps({"role": Role.ADMIN})
'{"role": "admin"}' — no custom encoder needed

3auto() and IntFlag for Combinable States

auto() removes the need to hand-assign a value when the specific underlying value is irrelevant — only distinctness and, for IntEnum/IntFlag, ordering matter. By default it assigns increasing integers starting at 1, but you can override _generate_next_value_ on the enum class for custom auto-numbering schemes, such as string values derived from the member name.

IntFlag (and its string cousin, StrFlag conceptually, via Flag) is a distinct enum variant designed for *combinable* states — permission sets, feature flags, style attributes — where more than one member can be 'active' simultaneously. Members combine with the bitwise | operator, membership is tested with in, and auto() inside an IntFlag automatically assigns powers of two (1, 2, 4, 8...) so combinations don't collide.

The distinction to internalize: a regular Enum (or IntEnum) models 'exactly one of these states' — an order is either PENDING or SHIPPED, never both — while IntFlag models 'any subset of these states' — a user can have READ and WRITE without EXECUTE. Reaching for the wrong one is a common design smell: representing a permission set as a plain Enum forces awkward workarounds like a separate member for every combination.

āœ•
—
+
from enum import Enum, auto

class Direction(Enum):
    NORTH = auto()
    SOUTH = auto()
    EAST = auto()
    WEST = auto()

print(Direction.NORTH.value)  # 1
localhost:3000
Bitwise Combination
Permission.WRITE in (Permission.READ | Permission.WRITE)
True

4Step-by-Step Breakdown

"pending", "PENDING", "Pending" — three ways to introduce a bug with a single typo. Enums make that class of mistake a static-checker error instead of a runtime surprise.

A plain Enum gives each member a name and a value. Compare members by identity, never by their raw value string.

Checkpoint: What is the idiomatic way to compare a status value against a known state?

  • →status == OrderStatus.PENDING (compare the enum member itself)
  • →status.value == "pending" (compare the raw string)

StrEnum (3.11+) lets members behave as actual strings too — useful when you need to serialize directly to JSON or compare with a raw string.

auto() assigns values automatically when you don't care about the underlying value, just distinctness.

Checkpoint: What does auto() do inside an Enum class body?

  • →Automatically assigns a distinct value, since the specific value does not matter
  • →Assigns a random, non-deterministic value on every run

IntFlag lets you combine members with bitwise OR — perfect for permission sets where multiple flags can be active at once.

With named constants and data shapes covered, __slots__ rounds out this section by addressing memory efficiency for classes with many instances.

Advance a Real Enum State. Finish next_status(): auto() assigns incrementing values so you never track them yourself.

Level Up šŸš€

Advanced cheat sheets, SEO tricks, and interview prep for this topic.

Browser Support

ChromeSupported

Fully supported (via server-side Python execution).

FirefoxSupported

Fully supported (via server-side Python execution).

SafariSupported

Fully supported (via server-side Python execution).

EdgeSupported

Fully supported (via server-side Python execution).

Best Practices

Compare enum members by identity, never by .value

status == OrderStatus.PENDING preserves type safety; status.value == "pending" reintroduces the exact typo-prone string comparison enums exist to prevent.

Reach for StrEnum/IntEnum only at serialization or interop boundaries

Mixing in str or int makes an enum equal to raw values from outside your code, which is exactly what you want at an API/JSON boundary but reduces safety everywhere else — keep plain Enum for purely internal logic.

Frequent Bugs

THE BUG

Modeling a set of independently-combinable flags (like permissions) as a plain Enum, then resorting to awkward extra members for every combination (READ_WRITE, READ_WRITE_EXECUTE, ...).

THE FIX

Use IntFlag with auto() for any state where more than one value can be active simultaneously; combine with | and test membership with in, instead of enumerating every combination by hand.

Real-World Examples

Validating a Status Transition State Machine

An order-processing system needs to enforce that orders can only move PENDING → SHIPPED → DELIVERED, never skip a step or move backward.

from enum import Enum

class OrderStatus(Enum):
    PENDING = "pending"
    SHIPPED = "shipped"
    DELIVERED = "delivered"

VALID_TRANSITIONS = {
    OrderStatus.PENDING: {OrderStatus.SHIPPED},
    OrderStatus.SHIPPED: {OrderStatus.DELIVERED},
    OrderStatus.DELIVERED: set(),
}

def can_transition(current: OrderStatus, target: OrderStatus) -> bool:
    return target in VALID_TRANSITIONS[current]

Interview Prep

?Frequently Asked Questions

Pascual Vila

Pascual Vila

Frontend Instructor // Code Syllabus

Common Pitfalls & Errors

The Error //

Comparing an enum member against its raw value (status.value == "pending") instead of against the member itself, silently defeating the enum's typo protection.

# Wrong: reintroduces string-typo risk if status.value == "Pending": # typo: capital P, silently never matches ... # Correct: AttributeError immediately if mistyped if status == OrderStatus.PENDING: ...

The Solution //

Compare against the member directly: status == OrderStatus.PENDING. If you truly need the raw value for serialization, convert at that specific boundary, not throughout your comparison logic.

Lesson Glossary

[01]Enum

A standard library class (enum module) for defining a closed set of named, distinct constant members.

Code Preview
// Enum context

[02]StrEnum

An enum variant (3.11+) whose members are also instances of str, so they compare equal to and serialize as raw string values.

Code Preview
// StrEnum context

[03]auto()

A helper that automatically assigns a distinct value to an enum member, used when the specific underlying value does not matter.

Code Preview
// auto() context

[04]IntFlag

An enum variant designed for combinable states, supporting bitwise | combination and in membership testing, typically auto-numbered as powers of two.

Code Preview
// IntFlag context

Continue Learning