The essentials

Quick reference

One focused task per row. Jump to the related section for complete, working examples.

UseSyntaxExamples
Declare an enumclass Color(Enum): RED = 1View examples
Look up by valuemember = Color(1)View examples
Look up by namemember = Color['RED']View examples
Read member metadataname, value = member.name, member.valueView examples
Iterate canonical membersmembers = list(Color)View examples
Declare an aliasCRIMSON = REDView examples
Inspect names including aliasesnames = Color.__members__View examples
Reject duplicate values@uniqueView examples
Generate enum valuesPENDING = auto()View examples
Create string-compatible membersclass Format(StrEnum): JSON = auto()View examples
Create integer-compatible membersclass ExitCode(IntEnum): OK = 0View examples
Declare bit flagsclass Permission(Flag): READ = auto()View examples
Combine flagsaccess = Permission.READ | Permission.WRITEView examples
Test a contained flagallowed = Permission.WRITE in accessView examples
Customize missing-value lookup_missing_ = classmethod(normalize_missing_value)View examples
Add member behaviordef can_retry(self): return self is State.FAILEDView examples
Build an enum dynamicallyLevel = Enum('Level', ['LOW', 'HIGH'])View examples
Verify enum constraints@verify(CONTINUOUS)View examples

Enums group symbolic names into a distinct type, making states, modes, protocol values, and bit masks harder to confuse with unrelated literals. Prefer Enum when identity and type separation matter, StrEnum or IntEnum only when compatibility with existing string or integer APIs is required, and Flag for values that may be combined. Treat member values as an external contract only when persistence or interoperability actually requires it.

Step by step

Detailed examples

01

Declare, inspect, and look up enum members

An Enum member is a singleton instance of its enum class. Use dotted access when the name is known in source code, subscription for a dynamic name, and a class call for lookup by value. Iteration preserves definition order and yields canonical members. Plain Enum members compare by identity and do not compare equal to their raw values, preserving separation between domains that happen to use the same underlying value.

Access members by name and value
from enum import Enum

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

member = Color['GREEN']
print(member is Color.GREEN)
print(Color(3).name, Color.BLUE.value)
print([color.name for color in Color])
print(Color.RED == 1)
Output
True
BLUE 3
['RED', 'GREEN', 'BLUE']
False
Back to quick reference ↑
02

Choose deliberately between aliases and unique values

When two names receive the same value, the later name is normally an alias of the first member. Aliases are absent from ordinary iteration but visible in __members__, and by-value lookup returns the canonical first member. This is useful for migrations and compatible vocabulary. Apply @unique when every name must have a distinct value; it checks the completed class and raises ValueError if aliases exist.

Inspect a deliberate compatibility alias
from enum import Enum

class Color(Enum):
    RED = 1
    CRIMSON = 1
    BLUE = 2

print(Color.CRIMSON is Color.RED)
print([member.name for member in Color])
print(list(Color.__members__))
print(Color(1).name)
Output
True
['RED', 'BLUE']
['RED', 'CRIMSON', 'BLUE']
RED
Back to quick reference ↑
03

Generate values with auto and StrEnum

auto() delegates to _generate_next_value_: plain Enum and IntEnum ordinarily generate increasing integers from 1, Flag generates powers of two, and StrEnum generates the lower-cased member name. StrEnum was added in Python 3.11 and is both str and Enum, which helps replace existing textual constants. Some libraries require type(value) is str rather than isinstance(value, str); pass str(member) at those strict boundaries.

Create stable textual constants with StrEnum
from enum import StrEnum, auto

class Format(StrEnum):
    JSON = auto()
    CSV = auto()
    TEXT = 'plain-text'

print(Format.JSON.value)
print(str(Format.TEXT))
print(isinstance(Format.CSV, str))
print([item.value for item in Format])
Output
json
plain-text
True
['json', 'csv', 'plain-text']
Back to quick reference ↑
04

Use IntEnum only at integer compatibility boundaries

IntEnum members are integers and compare equal to matching int values, making them suitable for replacing legacy numeric constants. That convenience weakens type separation: equal-valued members of unrelated IntEnum classes can compare equal through integer semantics, and ordinary arithmetic returns plain int results. Since Python 3.11, str() on an IntEnum member uses int.__str__. Prefer plain Enum for new domain models unless integer interoperability is a requirement.

Observe IntEnum compatibility and arithmetic
from enum import IntEnum

class ExitCode(IntEnum):
    OK = 0
    RETRY = 75

print(ExitCode.OK == 0)
print(str(ExitCode.RETRY))
result = ExitCode.RETRY + 1
print(result, type(result).__name__)
print(ExitCode(0).name)
Output
True
75
76 int
OK
Back to quick reference ↑
05

Represent independent options with Flag

Flag members support bitwise union, intersection, exclusive-or, and inversion while preserving the flag type. auto() assigns powers of two so individual members combine without overlapping bits. Flag containment and iteration over a composite value were added in Python 3.11. Use Flag for internal symbolic combinations; choose IntFlag only when the combined value must interoperate with integer-based APIs, and decide explicitly how unknown bits should be handled.

Combine and inspect permissions
from enum import Flag, auto

class Permission(Flag):
    READ = auto()
    WRITE = auto()
    EXECUTE = auto()

access = Permission.READ | Permission.WRITE
print(Permission.WRITE in access)
print(Permission.EXECUTE in access)
print([item.name for item in access])
print((access & Permission.READ).name)
Output
True
False
['READ', 'WRITE']
READ
Back to quick reference ↑
06

Normalize external values with _missing_

Calling an enum class performs by-value lookup and invokes _missing_ when no member is found. Override it as a class method to normalize a documented external representation, returning a member or None. Keep lookup deterministic and narrowly scoped; silently mapping arbitrary invalid values to a default can hide corrupt data. The hook only affects value lookup such as BuildMode('FAST'), not name lookup such as BuildMode['FAST'].

Accept case-insensitive string values
from enum import StrEnum

class BuildMode(StrEnum):
    DEBUG = 'debug'
    RELEASE = 'release'

    @classmethod
    def _missing_(cls, value):
        if isinstance(value, str):
            normalized = value.casefold()
            for member in cls:
                if member.value == normalized:
                    return member
        return None

print(BuildMode('DEBUG').name)
print(BuildMode('Release').value)
try:
    BuildMode('preview')
except ValueError:
    print('invalid mode')
Output
DEBUG
release
invalid mode
Back to quick reference ↑
07

Attach domain behavior without extending member enums

Enums are classes, so methods and properties can express behavior shared by their members. Existing enums that define members cannot be subclassed to add more members because that would break their identity and type invariants; share behavior through an empty enum base or ordinary mixin instead. Keep unrelated service logic outside the enum so the symbolic type remains focused.

Ask state members about allowed transitions
from enum import Enum

class State(Enum):
    PENDING = 'pending'
    RUNNING = 'running'
    FAILED = 'failed'
    COMPLETE = 'complete'

    def can_retry(self):
        return self is State.FAILED

    def can_finish(self):
        return self is State.RUNNING

for state in (State.PENDING, State.RUNNING, State.FAILED):
    print(state.value, state.can_retry(), state.can_finish())
Output
pending False False
running False True
failed True False
Back to quick reference ↑
08

Create dynamic enums and validate integer layouts

The functional API is useful when member names come from configuration or generated metadata; its start argument controls the first automatic integer value. Classes created dynamically must remain importable by a stable qualified name if they will be pickled. Python 3.11 added @verify with checks including UNIQUE, CONTINUOUS, and NAMED_FLAGS; @unique remains the broadly compatible way to reject aliases on older supported versions.

Generate levels and verify continuous codes
from enum import CONTINUOUS, Enum, IntEnum, verify

Level = Enum('Level', ['LOW', 'MEDIUM', 'HIGH'], start=10)

@verify(CONTINUOUS)
class HttpClass(IntEnum):
    INFORMATIONAL = 1
    SUCCESS = 2
    REDIRECTION = 3

print([(item.name, item.value) for item in Level])
print([item.value for item in HttpClass])
Output
[('LOW', 10), ('MEDIUM', 11), ('HIGH', 12)]
[1, 2, 3]
Back to quick reference ↑

Local code tester

Model states and feature flags

Add states, combine capabilities, and compare strict Enum identity with Flag membership.

Runs in your browser
Output
Press Run to load Python locally.

Sources and further reading

References

Authoritative documentation used to verify and expand this cheat sheet.

  1. Python Software Foundationenum — Support for enumerationsdocs.python.org
  2. Python Software FoundationEnum HOWTOdocs.python.org
  3. Python Software FoundationPEP 435 — Adding an Enum type to the Python standard librarypeps.python.org
  4. Python Software FoundationData model — Basic customizationdocs.python.org

Help us improve

Found a typo or missing example?

Tell us what would make this cheat sheet clearer, more complete, or more useful.

Share feedback