Lesson 33 · Intermediate · 18 min

Python Enums

Name a fixed set of values once and use the names everywhere.

enumsEnum memberslookupiteration

Someone types 'medum' into the size field and the price lookup returns nothing. A fixed set of names would have caught it at the door. Why is an Enum safer than a bare string?

An Enum gives a fixed set of named values a proper type. Members are unique objects, which makes comparisons and valid choices clearer than passing around bare strings. The name and value are both available when you need to display or serialize a member. You will also keep auto values internal, combine permissions, and validate stored values.

Define named members

Subclass Enum and assign names to values. Color.RED is a member object, not the string "red". Use .name for the identifier and .value for the underlying value. Members compare by identity.

from enum import Enum

class Color(Enum):
    RED = "red"
    GREEN = "green"

print(Color.RED.value)
print(Color.RED.name)

Names with stable values

Iterate over the members

An Enum class is iterable in definition order. This is useful for building menus, validating choices, and generating documentation. Iteration yields members, not their raw values.

from enum import Enum

class Color(Enum):
    RED = "red"
    GREEN = "green"

for color in Color:
    print(color.name, color.value)

A small fixed set

Look up by value or name

Calling the enum with a value returns the matching member, or raises ValueError if there is none. Square brackets look up by member name and raise KeyError when the name is unknown. Choose the lookup that matches your input.

from enum import Enum

class Color(Enum):
    RED = "red"
    GREEN = "green"

print(Color("green"))
print(Color["RED"])

Two kinds of lookup

auto() values are an implementation detail

auto() assigns consecutive integers, which is convenient inside the program but a poor storage format. The numbers can change when members are inserted. @unique catches accidental aliases, where two names receive the same value.

from enum import Enum, auto, unique

@unique
class Stage(Enum):
    NEW = auto()
    PAID = auto()
    SHIPPED = auto()

print([(stage.name, stage.value) for stage in Stage])
print(Stage.PAID is Stage(2))

Names are stable; auto numbers are local

Combine permissions with Flag

Flag members are bit values that can be combined with |. Test a permission with a bitwise AND and an equality check, not by comparing the whole combined value. Store the combined integer only if your boundary has a documented format.

from enum import Flag, auto

class Permission(Flag):
    READ = auto()
    WRITE = auto()
    ADMIN = READ | WRITE

editor = Permission.READ | Permission.WRITE
print(editor)
print((editor & Permission.READ) == Permission.READ)
print((editor & Permission.ADMIN) == Permission.ADMIN)

Bit flags for small permission sets

Store the value, validate on the way back

Enum members are not JSON values. Store member.value at the boundary, then call the enum class to validate and reconstruct the member. An unknown stored value raises ValueError, which is exactly the failure you want instead of silently accepting a typo.

from enum import Enum

class Plan(Enum):
    FREE = "free"
    PRO = "pro"

payload = {"plan": Plan.PRO.value}
restored = Plan(payload["plan"])
print(restored.name, restored.value)
try:
    Plan("team")
except ValueError as error:
    print(type(error).__name__, error)

A value at rest, a member in code

Key points

  • Enum members are unique objects with a name and a value.
  • Use .name and .value to access the parts.
  • Iteration yields members in definition order.
  • Color(value) looks up by value; Color[name] looks up by name.
  • Invalid lookups raise ValueError or KeyError depending on the method.
  • Do not persist auto values; use Flag for combinations; validate stored enum values.

Common mistakes

  • Comparing an enum member to its raw value and expecting equality.
  • Using a bare string where a closed set of choices is required.
  • Forgetting that lookup by value and lookup by name are different.
  • Writing an Enum member directly into JSON and assuming it serializes as its value.
Your turn

Define a Color enum with RED and GREEN, then print Color.RED.value and look up Color('green').

Try it yourself

Change the values, predict the output, then run the code. The Python runtime is downloaded the first time you press Run, so the first run can take a few seconds.

In-browser PythonRuns locally · no account
First run downloads Pyodide from a CDN. Use Run code after editing.

Practice this lesson

12 questions with immediate explanations.

See all 12 answersStart practice
← functoolsCSV files →