Today we’ll be talking about the named tuple.
Here’s the video version if you feel like watching it first:
Regular Tuples
Well, you sure know what tuples are. Tuples are immutable and we can access their elements by index.
On the other hand we have dictionaries where we can access elements by keys and classes where we can use attributes with meaningful names. This is often more readable than indices.
Named tuples sort of combine the two ways of accessing elements: we can use both indices and attribute names.
To see the difference between a regular tuple and a named tuple, let’s first create a simple program with a regular one:
book = ("Furious Tapeworms", "Mary Rumble", 1521, [2001, 2006, 2015])
print(f'"{book[0]}" by {book[1]}, {book[2]} fascinating pages')
print("Editions: ")
for edition in book[3]:
print(edition)
Here’s the output:
"Furious Tapeworms" by Mary Rumble, 1521 fascinating pages
Editions:
2001
2006
2015
Use a Named Tuple Instead
And now let’s rewrite this program replacing the tuple with a named tuple.
In order to use named tuples, we have to import the extension type namedtuple from the collections module:
from collections import namedtuple
Book = namedtuple('Book', ['title', 'author', 'pagecount', 'editions'])
book = Book(title = "Furious Tapeworms",
author = "Mary Rumble",
pagecount = 1521,
editions = [2001, 2006, 2015])
print(f'"{book.title}" by {book.author}, {book.pagecount} fascinating pages')
print("Editions: ")
for edition in book.editions:
print(edition)
The output is the same, but this syntax is more readable. You could also access the elements of a named tuple just like those of a regular tuple:
from collections import namedtuple
Book = namedtuple('Book', ['title', 'author', 'pagecount', 'editions'])
book = Book(title = "Furious Tapeworms",
author = "Mary Rumble",
pagecount = 1521,
editions = [2001, 2006, 2015])
print(f'"{book[0]}" by {book[1]}, {book[2]} fascinating pages')
print("Editions: ")
for edition in book[3]:
print(edition)
Let’s have a closer look at how named tuples are created:
Book = namedtuple('Book', ['title', 'author', 'pagecount', 'editions'])
A named tuple requires at least two arguments: typename and field_names.
namedtuple is a factory function which returns a new tuple subclass with the name specified as the typename argument, in our case ‘Book’.
The second argument, field_names, is a sequence of strings. The subclass returned by the namedtuple factory function is used to create objects that behave like tuples, but their elements can be accessed not only by indices, but also by attribute names specified as the strings in the field_names sequence. So, in our case, the elements can be accessed by means of the attribute names title, author, pagecount and editions.
In the example above the field_names argument is a list, but alternatively we could use a string. If so, we’d have to separate the attribute names with whitespaces:
from collections import namedtuple
Book = namedtuple('Book', 'title author pagecount editions')
book = Book(title = "Furious Tapeworms",
author = "Mary Rumble",
pagecount = 1521,
editions = [2001, 2006, 2015])
print(f'"{book.title}" by {book.author}, {book.pagecount} fascinating pages')
print("Editions: ")
for edition in book.editions:
print(edition)
We can instantiate our named tuple with keyword arguments like above, but we can also use positional arguments:
from collections import namedtuple
Book = namedtuple('Book', 'title author pagecount editions')
book = Book("Furious Tapeworms",
"Mary Rumble",
1521,
[2001, 2006, 2015])
print(f'"{book.title}" by {book.author}, {book.pagecount} fascinating pages')
print("Editions: ")
for edition in book.editions:
print(edition)
or both positional and keyword arguments. In such a case the positional ones must come first:
from collections import namedtuple
Book = namedtuple('Book', 'title author pagecount editions')
book = Book("Furious Tapeworms",
"Mary Rumble",
pagecount = 1521,
editions = [2001, 2006, 2015])
print(f'"{book.title}" by {book.author}, {book.pagecount} fascinating pages')
print("Editions: ")
for edition in book.editions:
print(edition)
Now let’s use our example in interactive mode to demonstrate how named tuples can be used:
>>> from collections import namedtuple
>>> Book = namedtuple('Book', 'title author pagecount editions')
>>> book = Book(title = "Furious Tapeworms",
... author = "Mary Rumble",
... pagecount = 1521,
... editions = [2001, 2006, 2015])
...
>>> book[1], book[3][0] # access by index
('Mary Rumble', 2001)
>>> book.author, book.editions[0] # access by attribute name
('Mary Rumble', 2001)
>>> book_title, book_author, book_pages, book_editions = book # unpacking
>>> book_title, book_author, book_pages, book_editions
('Furious Tapeworms', 'Mary Rumble', 1521, [2001, 2006, 2015])
>>> book # readable string representation
Book(title='Furious Tapeworms', author='Mary Rumble', pagecount=1521, editions=[2001, 2006, 2015])
Named Tuple Methods
Finally, let’s mention the methods we can use with named tuples. We can use all the methods inherited from the tuple class, but also some more.
So, the first named tuple method is _make. We use it to create a named tuple from a sequence or iterable:
>>> a_list = ["Furious Tapeworms Part 2", "Mary Rumble", 31452, [2016, 2018]]
>>> Book._make(a_list)
Book(title='Furious Tapeworms Part 2', author='Mary Rumble', pagecount=31452, editions=[2016, 2018])
>>> a_tuple = ("Furious Tapeworms Defeated", "John Rumble", 4, [2017, 2018])
>>> Book._make(a_tuple)
Book(title='Furious Tapeworms Defeated', author='John Rumble', pagecount=4, editions=[2017, 2018])
We can even use a string or a range if it makes sense. It doesn’t make sense here, but at least you can see how it works:
>>> a_string = 'AP62'
>>> Book._make(a_string)
Book(title='A', author='P', pagecount='6', editions='2')
>>> a_range = range(4)
>>> Book._make(a_range)
Book(title=0, author=1, pagecount=2, editions=3)
Let me mention just one more method, _asdict. It returns an ordered dictionary, so a dictionary containing key-value pairs, which additionally takes into consideration the order the elements were added in. Here’s how it works:
>>> book # as named tuple
Book(title='Furious Tapeworms', author='Mary Rumble', pagecount=1521, editions=[2001, 2006, 2015])
>>> book._asdict() # as ordered dictionary
OrderedDict([('title', 'Furious Tapeworms'), ('author', 'Mary Rumble'), ('pagecount', 1521), ('editions', [2001, 2006, 2015])])
If need arises, you can make a regular dictionary like so:
>>> dict(book._asdict()) # as regular dictionary
{'title': 'Furious Tapeworms', 'author': 'Mary Rumble', 'pagecount': 1521, 'editions': [2001, 2006, 2015]}
If we have a regular dictionary, which we want to turn into a named tuple, we can use the ** operator like so:
>>> my_favorite_book = {'title': 'Sarah Strikes Back',
... 'author': 'Ben Struck',
... 'pagecount': 425,
... 'editions': [1825, 1865, 1879, 1911, 1954, 2001]}
>>> Book(**my_favorite_book)
Book(title='Sarah Strikes Back', author='Ben Struck', pagecount=425, editions=[1825, 1865, 1879, 1911, 1954, 2001])