What's the purpose of enums? What value do they create for the language? When should I use them and when should I avoid them?

The Enum type got into Python via PEP 435. The reasoning given is:

The properties of an enumeration are useful for defining an immutable, related set of constant values that may or may not have a semantic meaning.

When using numbers and strings for this purpose, they could be characterized as "magic numbers" or "magic strings". Numbers rarely carry with them the semantics, and strings are easily confused (capitalization? spelling? snake or camel-case?)

Days of the week and school letter grades are examples of this kind of collections of values.

Here's an example from the docs:

from enum import Enum

class Color(Enum):
    red = 1
    green = 2
    blue = 3

Like the bare class, this is much more readable and elegant than the namedtuple example, it is also immutable, and it has further benefits as we'll see below.

Strictly dominant: The type of the enum member is the enum

>>> type(Color.red)
<enum 'Color'>
>>> isinstance(Color.green, Color)
True

This allows you to define functionality on the members in the Enum definition. Defining functionality on the values could be accomplished with the other prior methods, but it would be very inelegant.

Improvement: String coercion

The string representation is human readable, while the repr has more information:

>>> print(Color.red)
Color.red
>>> print(repr(Color.red))
<Color.red: 1>

I find this to be an improvement over the magic numbers and even possibly better than strings from the namedtuple.

Iteration (parity):

The enum supports iteration (like the namedtuple, but not so much the bare class) too:

>>> for color in Color:
        print(color)
Color.red
Color.green
Color.blue

The __members__ attribute is an ordered mapping of the names of the enums to their respective enum objects (similar to namedtuple's _asdict() function).

>>> Color.__members__
mappingproxy(OrderedDict([('red', <Color.red: 1>), ('green', <Color.green: 2>), 
('blue', <Color.blue: 3>)]))

Supported by pickle (parity)

You can serialize and deserialize the enum (in case anyone was worried about this):

>>> import pickle
>>> color.red is pickle.loads(pickle.dumps(color.red))
True

Improvement: Aliases

This is a nice feature that the bare class doesn't have, and it would be difficult to tell the alias was there in the namedtuple.

class Color(Enum):
    red = 1
    green = 2
    blue = 3
    really_blue = 3

The alias comes after the canonical name, but they are both the same:

>>> Color.blue is Color.really_blue
True

If aliases should be prohibited to avoid value collisions, use the enum.unique decorator (a strictly dominant feature).

Strictly dominant: comparisons done with is

The enum is intended to be tested with is, which is a fast check for a single object's identity in the process.

>>> Color.red is Color.red
True
>>> Color.red is Color.blue
False
>>> Color.red is not Color.blue
True

Tests for equality work as well, but tests for identity with is are optimal.

Different semantics from other Python classes

Enum classes have different semantics from regular Python types. The values of the Enum are instances of the Enum, and are singletons in memory for those values - there is no other purpose for instantiating them.

>>> Color.red is Color(1)

This is important to keep in mind, perhaps it is a downside, but comparing on this dimension is comparing apples with oranges.

Enums not assumed to be ordered

While the Enum class knows what order the members are created in, enums are not assumed to be ordered. This is a feature because many things that may be enumerated have no natural order, and therefore order would be arbitrary.

However, you can give your enums order (see the next section).

Subclassing

You can't subclass an Enum with members declared, but you can subclass an Enum that doesn't declare members to share behavior (see the OrderedEnum recipe in the docs).

This is a feature - it makes little sense to subclass an Enum with members, but again, the comparison is apples and oranges.

When should I use enum.Enum?

This is the new canonical enumeration in Python. Collaborators will expect your enums to behave like these enums.

Use it anywhere you have a canonical source of enumerated data in your code where you want explicitly specified to use the canonical name, instead of arbitrary data.

For example, if in your code you want users to state that it's not "Green", "green", 2, or "Greene", but Color.green - use the enum.Enum object. It's both explicit and specific.

There are a lot of examples and recipes in the documentation.

When should I avoid them?

Stop rolling your own or letting people guess about magic numbers and strings. Don't avoid them. Embrace them.

However, if your enum members are required to be integers for historic reasons, there's the IntEnum from the same module, which has the same behavior, but is also an integer because it subclasses the builtin int before subclassing Enum. From IntEnum's help:

class IntEnum(builtins.int, Enum)

we can see that the IntEnum values would test as an instance of an int.

Answer from Aaron Hall on Stack Overflow
🌐
Python
docs.python.org › 3 › library › enum.html
enum — Support for enumerations
February 23, 2026 - >>> class Color(Enum): ... _order_ = 'RED GREEN BLUE' ... RED = 1 ... BLUE = 3 ... GREEN = 2 ... Traceback (most recent call last): ... TypeError: member order does not match _order_: ['RED', 'BLUE', 'GREEN'] ['RED', 'GREEN', 'BLUE'] ... In Python 2 code the _order_ attribute is necessary as definition order is lost before it can be recorded.
🌐
Python documentation
docs.python.org › 3 › howto › enum.html
Enum HOWTO — Python 3.14.3 documentation
An Enum is a set of symbolic names bound to unique values. They are similar to global variables, but they offer a more useful repr(), grouping, type-safety, and a few other features. They are most ...
🌐
GeeksforGeeks
geeksforgeeks.org › python › enum-in-python
enum in Python - GeeksforGeeks
December 11, 2025 - Enums in Python are used to define a set of named constant values. They make code cleaner, more readable and prevent using invalid values.
🌐
Mimo
mimo.org › glossary › python › enum
Python enum: simplify code with easy-to-read enumerations
Start your coding journey with Python. Learn basics, data types, control flow, and more ... from enum import Enum # 1. Define the Enum class class Status(Enum): PENDING = 1 IN_PROGRESS = 2 COMPLETED = 3 FAILED = 4 # 2. Access an enum member current_status = Status.IN_PROGRESS print(current_status) # Outputs: Status.IN_PROGRESS # 3.
🌐
Real Python
realpython.com › python-enum
Build Enumerations of Constants With Python's Enum – Real Python
December 15, 2024 - Python’s enum module offers a way to create enumerations, a data type allowing you to group related constants. You can define an enumeration using the Enum class, either by subclassing it or using its functional API.
🌐
Codecademy
codecademy.com › docs › python › enum
Python | enum | Codecademy
December 19, 2024 - Enum (short for enumeration) is a class in Python used to define a set of named, immutable constants. Enumerations improve code readability and maintainability by replacing magic numbers or strings with meaningful names.
🌐
ArjanCodes
arjancodes.com › blog › python-enum-classes-for-managing-constants
Python Enums: Effective Constant Management Techniques | ArjanCodes
July 1, 2024 - Enums in Python are a powerful tool for defining and managing sets of constants. By using different types of enums like Enum, IntEnum, Flag, and IntFlag, readability is improved, errors are minimized, and flexibility is increased.
Top answer
1 of 1
269

What's the purpose of enums? What value do they create for the language? When should I use them and when should I avoid them?

The Enum type got into Python via PEP 435. The reasoning given is:

The properties of an enumeration are useful for defining an immutable, related set of constant values that may or may not have a semantic meaning.

When using numbers and strings for this purpose, they could be characterized as "magic numbers" or "magic strings". Numbers rarely carry with them the semantics, and strings are easily confused (capitalization? spelling? snake or camel-case?)

Days of the week and school letter grades are examples of this kind of collections of values.

Here's an example from the docs:

from enum import Enum

class Color(Enum):
    red = 1
    green = 2
    blue = 3

Like the bare class, this is much more readable and elegant than the namedtuple example, it is also immutable, and it has further benefits as we'll see below.

Strictly dominant: The type of the enum member is the enum

>>> type(Color.red)
<enum 'Color'>
>>> isinstance(Color.green, Color)
True

This allows you to define functionality on the members in the Enum definition. Defining functionality on the values could be accomplished with the other prior methods, but it would be very inelegant.

Improvement: String coercion

The string representation is human readable, while the repr has more information:

>>> print(Color.red)
Color.red
>>> print(repr(Color.red))
<Color.red: 1>

I find this to be an improvement over the magic numbers and even possibly better than strings from the namedtuple.

Iteration (parity):

The enum supports iteration (like the namedtuple, but not so much the bare class) too:

>>> for color in Color:
        print(color)
Color.red
Color.green
Color.blue

The __members__ attribute is an ordered mapping of the names of the enums to their respective enum objects (similar to namedtuple's _asdict() function).

>>> Color.__members__
mappingproxy(OrderedDict([('red', <Color.red: 1>), ('green', <Color.green: 2>), 
('blue', <Color.blue: 3>)]))

Supported by pickle (parity)

You can serialize and deserialize the enum (in case anyone was worried about this):

>>> import pickle
>>> color.red is pickle.loads(pickle.dumps(color.red))
True

Improvement: Aliases

This is a nice feature that the bare class doesn't have, and it would be difficult to tell the alias was there in the namedtuple.

class Color(Enum):
    red = 1
    green = 2
    blue = 3
    really_blue = 3

The alias comes after the canonical name, but they are both the same:

>>> Color.blue is Color.really_blue
True

If aliases should be prohibited to avoid value collisions, use the enum.unique decorator (a strictly dominant feature).

Strictly dominant: comparisons done with is

The enum is intended to be tested with is, which is a fast check for a single object's identity in the process.

>>> Color.red is Color.red
True
>>> Color.red is Color.blue
False
>>> Color.red is not Color.blue
True

Tests for equality work as well, but tests for identity with is are optimal.

Different semantics from other Python classes

Enum classes have different semantics from regular Python types. The values of the Enum are instances of the Enum, and are singletons in memory for those values - there is no other purpose for instantiating them.

>>> Color.red is Color(1)

This is important to keep in mind, perhaps it is a downside, but comparing on this dimension is comparing apples with oranges.

Enums not assumed to be ordered

While the Enum class knows what order the members are created in, enums are not assumed to be ordered. This is a feature because many things that may be enumerated have no natural order, and therefore order would be arbitrary.

However, you can give your enums order (see the next section).

Subclassing

You can't subclass an Enum with members declared, but you can subclass an Enum that doesn't declare members to share behavior (see the OrderedEnum recipe in the docs).

This is a feature - it makes little sense to subclass an Enum with members, but again, the comparison is apples and oranges.

When should I use enum.Enum?

This is the new canonical enumeration in Python. Collaborators will expect your enums to behave like these enums.

Use it anywhere you have a canonical source of enumerated data in your code where you want explicitly specified to use the canonical name, instead of arbitrary data.

For example, if in your code you want users to state that it's not "Green", "green", 2, or "Greene", but Color.green - use the enum.Enum object. It's both explicit and specific.

There are a lot of examples and recipes in the documentation.

When should I avoid them?

Stop rolling your own or letting people guess about magic numbers and strings. Don't avoid them. Embrace them.

However, if your enum members are required to be integers for historic reasons, there's the IntEnum from the same module, which has the same behavior, but is also an integer because it subclasses the builtin int before subclassing Enum. From IntEnum's help:

class IntEnum(builtins.int, Enum)

we can see that the IntEnum values would test as an instance of an int.

Find elsewhere
🌐
Medium
medium.com › @jaberi.mohamedhabib › understanding-enums-and-classes-in-python-db4a7dbf32e0
Understanding Enums and Classes in Python | by JABERI Mohamed Habib | Medium
March 3, 2024 - Understanding the roles of enums and classes in Python is essential for writing clean, maintainable, and organized code. Enums offer a way to represent named constant values, while classes provide a mechanism for defining custom objects with attributes and behavior.
🌐
Python
docs.python.org › 3.10 › library › enum.html
enum — Support for enumerations — Python 3.10.20 documentation
An enumeration is a set of symbolic names (members) bound to unique, constant values.
Top answer
1 of 16
3010

Enums have been added to Python 3.4 as described in PEP 435. It has also been backported to 3.3, 3.2, 3.1, 2.7, 2.6, 2.5, and 2.4 on pypi.

For more advanced Enum techniques try the aenum library (2.7, 3.3+, same author as enum34. Code is not perfectly compatible between py2 and py3, e.g. you'll need __order__ in python 2).

  • To use enum34, do $ pip install enum34
  • To use aenum, do $ pip install aenum

Installing enum (no numbers) will install a completely different and incompatible version.


from enum import Enum     # for enum34, or the stdlib version
# from aenum import Enum  # for the aenum version
Animal = Enum('Animal', 'ant bee cat dog')

Animal.ant  # returns <Animal.ant: 1>
Animal['ant']  # returns <Animal.ant: 1> (string lookup)
Animal.ant.name  # returns 'ant' (inverse lookup)

or equivalently:

class Animal(Enum):
    ant = 1
    bee = 2
    cat = 3
    dog = 4

In earlier versions, one way of accomplishing enums is:

def enum(**enums):
    return type('Enum', (), enums)

which is used like so:

>>> Numbers = enum(ONE=1, TWO=2, THREE='three')
>>> Numbers.ONE
1
>>> Numbers.TWO
2
>>> Numbers.THREE
'three'

You can also easily support automatic enumeration with something like this:

def enum(*sequential, **named):
    enums = dict(zip(sequential, range(len(sequential))), **named)
    return type('Enum', (), enums)

and used like so:

>>> Numbers = enum('ZERO', 'ONE', 'TWO')
>>> Numbers.ZERO
0
>>> Numbers.ONE
1

Support for converting the values back to names can be added this way:

def enum(*sequential, **named):
    enums = dict(zip(sequential, range(len(sequential))), **named)
    reverse = dict((value, key) for key, value in enums.iteritems())
    enums['reverse_mapping'] = reverse
    return type('Enum', (), enums)

This overwrites anything with that name, but it is useful for rendering your enums in output. It will throw a KeyError if the reverse mapping doesn't exist. With the first example:

>>> Numbers.reverse_mapping['three']
'THREE'

If you are using MyPy another way to express "enums" is with typing.Literal.

For example:

from typing import Literal #python >=3.8
from typing_extensions import Literal #python 2.7, 3.4-3.7


Animal = Literal['ant', 'bee', 'cat', 'dog']

def hello_animal(animal: Animal):
    print(f"hello {animal}")

hello_animal('rock') # error
hello_animal('bee') # passes

2 of 16
984

Before PEP 435, Python didn't have an equivalent but you could implement your own.

Myself, I like keeping it simple (I've seen some horribly complex examples on the net), something like this ...

class Animal:
    DOG = 1
    CAT = 2

x = Animal.DOG

In Python 3.4 (PEP 435), you can make Enum the base class. This gets you a little bit of extra functionality, described in the PEP. For example, enum members are distinct from integers, and they are composed of a name and a value.

from enum import Enum

class Animal(Enum):
    DOG = 1
    CAT = 2

print(Animal.DOG)
# <Animal.DOG: 1>

print(Animal.DOG.value)
# 1

print(Animal.DOG.name)
# "DOG"

If you don't want to type the values, use the following shortcut:

class Animal(Enum):
    DOG, CAT = range(2)

Enum implementations can be converted to lists and are iterable. The order of its members is the declaration order and has nothing to do with their values. For example:

class Animal(Enum):
    DOG = 1
    CAT = 2
    COW = 0

list(Animal)
# [<Animal.DOG: 1>, <Animal.CAT: 2>, <Animal.COW: 0>]

[animal.value for animal in Animal]
# [1, 2, 0]

Animal.CAT in Animal
# True
🌐
Python
typing.python.org › en › latest › spec › enums.html
Enumerations — typing documentation
class TrafficLight(Enum): RED = 1 GREEN = 2 YELLOW = 3 AMBER = YELLOW # Alias for YELLOW reveal_type(TrafficLight.AMBER) # Revealed type is Literal[TrafficLight.YELLOW] If using Python 3.11 or newer, the enum.member and enum.nonmember classes can be used to unambiguously distinguish members from non-members.
🌐
Tutorialspoint
tutorialspoint.com › python › python_enums.htm
Python - Enums
In Python, the term enumeration refers to the process of assigning fixed constant values to a set of strings so that each string can be identified by the value bound to it. The Enum class included in enum module (which is a part of Python's standard
🌐
Python
peps.python.org › pep-0435
PEP 435 – Adding an Enum type to the Python standard library | peps.python.org
Makes it easier to change the enum and extend it, especially for large enumerations. Cons: actually longer to type in many simple cases. The argument of explicit vs. implicit applies here as well. The Python standard library has many places where the usage of enums would be beneficial to replace other idioms currently used to represent them.
🌐
KDnuggets
kdnuggets.com › python-enum-how-to-build-enumerations-in-python
Python Enum: How To Build Enumerations in Python - KDnuggets
To sum up: An enum is essentially a collection of related constants, where each constant has a meaningful name associated with it. In Python, you can create enums using the enum module (which we’ll do shortly!).
🌐
W3Schools
w3schools.com › python › ref_module_enum.asp
Python enum Module
Python Examples Python Compiler Python Exercises Python Quiz Python Challenges Python Server Python Syllabus Python Study Plan Python Interview Q&A Python Bootcamp Python Certificate Python Training ... from enum import Enum class Color(Enum): RED = 1 GREEN = 2 BLUE = 3 print(Color.RED.name) print(Color.RED.value) Try it Yourself »
🌐
Readthedocs
pradyunsg-cpython-lutra-testing.readthedocs.io › en › latest › library › enum.html
enum — Support for enumerations - Python 3.12.0a0 documentation
EnumType is responsible for setting the correct __repr__(), __str__(), __format__(), and __reduce__() methods on the final enum, as well as creating the enum members, properly handling duplicates, providing iteration over the enum class, etc. ... In Python 3.12 it will be possible to check for member values and not just members; until then, a TypeError will be raised if a non-Enum-member is used in a containment check.
🌐
Plain English
python.plainenglish.io › a-practical-guide-to-python-enum-for-developers-5b6440e90da7
A Practical Guide to Python Enum for Developers | by Vijay | Python in Plain English
December 18, 2025 - Import Enum, define constants, use it. That part was easy. What I did not expect was how many small mistakes I would still make after that. So this is not a guide from docs. This is what I learned by messing up production code and then fixing… ... New Python content every day.
🌐
Codearmo
codearmo.com › python-tutorial › object-orientated-programming-enums
Python Enums | Codearmo
March 28, 2025 - from enum import unique @unique class ClientErrorResponses(Enum): BadRequest = 400 Unauthorized = 401 PaymentRequired = 402 Forbidden = 403 NotFound = 404 MethodNotAllowed = 405 NotAcceptable = 406 ProxyAuthRequired = 407 RequestTimeout = 408 Conflict = 409 Gone = 410 LengthRequired = 411 PreconditionFailed = 412 PayLoadTooLarge = 413 · If we were to try to add another error with one of the codes displayed above we would get an AttributeError. Python actually has a built in module for this exact task and they use enumerations!
🌐
GitHub
github.com › python › cpython › blob › main › Lib › enum.py
cpython/Lib/enum.py at main · python/cpython
# a new Enum called name, and export the enum and its members back to · # module; # also, replace the __reduce_ex__ method so unpickling works in · # previous Python versions · module_globals = sys.modules[module].__dict__ if source: source = source.__dict__ else: source = module_globals ·
Author   python