I would like to know what are the differences between enum and namedtuple and when one should use one over the other.
-
1Op should search a bit before asking. Look at theese topics: http://stackoverflow.com/questions/2970608/what-are-named-tuples-in-python and http://stackoverflow.com/questions/36932/how-can-i-represent-an-enum-in-python – Kiogara Nov 16 '16 at 13:03
2 Answers
As an analogy (albeit an imperfect one), you can think of enum.Enum
and namedtuple
in python as enum
and struct
in C. In other words, enum
s are a way of aliasing values, while namedtuple
is a way of encapsulating data by name. The two are not really interchangeable, and you can use enum
s as the named values in a namedtuple
.
I think this example illustrates the difference.
from collections import namedtuple
from enum import Enum
class HairColor(Enum):
blonde = 1
brown = 2
black = 3
red = 4
Person = namedtuple('Person', ['name','age','hair_color'])
bert = Person('Bert', 5, HairColor.black)
You can access the named "attributes" of the person the same way you would a regular object.
>>> print(bert.name)
Bert
>>> print(bert.age)
5
>>> print(bert.hair_color)
HairColor.black
>>> print(bert.hair_color.value)
3
You often don't see namedtuple
s like this because the same essential concept can be accomplished by using the more widely known class
declaration. The class
definition below behaves almost identically to the namedtuple
definition above.
class Person:
def __init__(self, name, age, hair_color):
self.name = name
self.age = age
self.hair_color = hair_color
However, a major difference between a namedtuple
and a class
object is that the attributes of a namedtuple
cannot be changed after its creation.

- 5,179
- 2
- 27
- 53
-
3You can also use `namedtuple`s as values for an enum... `class People(enum.Enum): john = Person('John', 21, HairColor.blonde)` – Bakuriu Nov 16 '16 at 13:33
-
-
So `enum`s are useful to get rid of magic numbers? I struggle to see good use cases. In [PEP 435](https://www.python.org/dev/peps/pep-0435/#status-of-discussions), it says: "which can allow us to replace many integer constants in the standard library by enums with friendly string representations, without ceding backwards compatibility." – Alex Povel Apr 29 '20 at 13:39
-
1@Alex, as far as I understand, `enum`s are useful for avoiding ambiguity and for performance (storing `int`s instead of bigger `str`s). I can tab-complete available enum values instead of guessing what the string version is (is it camel? all-caps? lowercase? --> use enum to avoid this). And when you're doing big data tables, instead of storing 10^8 strings, you can store smaller integers :) – 123 Oct 29 '20 at 16:58
The namedtuple is a fast structure that, using __slots__ instead of __dict__, finalizes the content you provide at initialization (that practically becomes read only, though a _replace() method exists).
A namedtuple is generally used when you need many (such as hundreds, thousands and even millions of) objects of the same type or you are reading and/or writing a record.
For instance, an often cited example is a Point namedtuple that might be used to work with a polygon vertex with its x, y, z
components.
The overhead introduced by a namedtuple over a regular tuple is minimal if compared to the benefit of always pointing to the right component by name (.x, .y, .z, ...) instead of by index (0, 1, 2, ...).
Reading code such as A.x is easier than A[0]: the meaning is evident, even months after you have written the code and, better, for other programmers as well.
Thus a namedtuple is fast, can be used to meaningfully identify the content of the tuple and, last but not least, may coexist with older code accessing a tuple content by index.
from collections import namedtuple
Point = namedtuple('Point', 'x y z') # note the x, y, z fields
origin = Point(0, 0, 0)
A = Point(1, 1, 1)
B = Point(1, 1, 0)
C = Point(1, 0, 0)
D = Point(1, 2, 3)
for p in (origin, A, B, C, D):
print(p)
print('x:', p.x, ' y:', p.y, ' z:', p.z)
print('x:', p[0], ' y:', p[1], ' z:', p[2])
print()
Going on from the example above, as soon as everything is accessing the points components by name instead of by index, further changes might be more easily introduced, by not going into changing any index number:
from collections import namedtuple
Point = namedtuple('Point', 'name x y z') # addition of the field 'name'
origin = Point('O', 0, 0, 0)
A = Point('A', 1, 1, 1)
B = Point('B', 1, 1, 0)
C = Point('C', 1, 0, 0)
D = Point('D', 1, 0, 1)
for p in (origin, A, B, C, D):
print(p)
print(p.name) # more readable than p[0] that is no more the x coordinate
print('x:', p.x, ' y:', p.y, ' z:', p.z) # unchanged
print('x:', p[1], ' y:', p[2], ' z:', p[3]) # changed
print()
An enumeration is a way to couple symbolic names to constant values and classify them as a specific set. We define an enumeration by creating a class derived from either Enum or IntEnum, depending on the values we want our constants to have: Enum is the generic version, IntEnum enforces the fact that every constant value will be of type int.
For instance, enums are good for defining colors by name, specific integer types, gender, or, again, - more generally - elements belonging to a specific set.
from enum import Enum, IntEnum, unique
class Color_1(Enum):
red = 'red'
green = 'green'
blue = 'blue'
class Color_2(Enum):
red = (255, 0, 0)
green = (0, 255, 0)
blue = (0, 0, 255)
class Color_3(IntEnum):
red = 0xFF0000
green = 0xFF00
blue = 0xFF
class Gender_1(Enum):
unknown = 'U'
male = 'M'
female = 'F'
class Gender_2(Enum):
unknown = 0.3
male = 0.5
female = 0.7
class Shape(Enum): # Note the different constants types, perfectly legal
TRIANGLE = 't'
RECTANGLE = 5
SQUARE = tuple('square')
class DataType(IntEnum):
int8 = -8
int16 = -16
int32 = -32
int64 = -64
int = -2
negative = -1
positive = 1
uint = 2
uint8 = 8
uint16 = 16
uint32 = 32
uint64 = 64
In the pythonic development - enumerations elements may have a specific value assigned - that can be either unique or not, depending on your preference and specification. The unique decorator is used to enforce values uniqueness. By default, it is possible to assign the same constant value to two or more different symbolic names.
class Color_4(IntEnum):
red = 1
green = 2
blue = 3
RED = 1
GREEN = 2
BLUE = 3
Enumerations elements can be compared with each other, but for them to be successful, not only must the value match, even their type must be the same.
For instance:
Color_4.red == Color_4.RED
will return True (same class, same value), but the following:
Shape.SQUARE == tuple('square')
will be False - because the right element of the comparison - tuple('square') - is not of type Shape, though both of them have the same value.
To conclude, enums and namedtuples are different instruments.
Enumerations have been added just recently to Python (search PEP435). If memory serves me right, namedtuples were available for quite a long time, but I am still a community newbie, thus I may be wrong. HTH

- 7,830
- 13
- 34
- 43

- 825
- 1
- 10
- 13
-
-
@Billy sorry, but you came here while I was writing the second part I added just now. – Alberto Vassena Nov 16 '16 at 17:42
-
From testing out the above with `IntEnum` I've noticed that the following comparison `Color_4.red == 1` results in `True`. However, when doing `1 in Color_4` it results in `False` (only when doing `Color_4.red in Color_4` would result in `True`) – Marc Nov 30 '17 at 19:33