I would like to know what are the differences between enum and namedtuple and when one should use one over the other.
In general, you can use namedtuple instances wherever you need a tuple-like object. Named tuples have the advantage that they provide a way to access their values using field names and the dot notation. This will make your code more Pythonic.
Tuples are immutable, whether named or not. namedtuple only makes the access more convenient, by using names instead of indices. You can only use valid identifiers for namedtuple , it doesn't perform any hashing — it generates a new type instead.
Python Namedtuple vs Dict – Difference explainedPython namedtuples are immutable while a dictionary is mutable in python. A namedtuple can be used to access elements in the tuple using the names and not just the indexes while the data in a python dict can be accessed using a key:value pairing.
Python namedtuple is an immutable container type, whose values can be accessed with indexes and named attributes. It has functionality like tuples with additional features. A named tuple is created with the collections. namedtuple factory function.
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.
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With