Improving your code readability with namedtuples

By Michael Anckaert - published on - posted in Python

This article was orginally published on The content is unchanged but I have updated formatting so the article is equally readable as before.

If you've programmed in Python for some time you've no doubt used to tuples to move around data in your code. Tuples are a very useful way of grouping related data in a single variable.One issue that often comes up with tuples is that they are very easy to abuse...

Abusing tuples

When passing along or returning tuples in your code, things usually go like this:

def bmi_risk(person_data):
    bmi = (person_data[2] / person_data[1]**2)
    if person_data[0] > 30 and bmi > 30:
        print("You're at risk because of a high BMI!")

At first glance this code isn't that bad. Using some expressive variable and function names we can easily determine that we are calculating a Body Mass Index and determining the risk a person has. But what's going on with that person_data  variable? We're lacking comments in our code and what's up with the comparison > 30 every time?

Take 2:

def bmi_risk(person_data):
    age = person_data[0]
    height = person_data[1]
    weight = person_data[2]
    bmi = (weight / height**2)
    if age > 30 and bmi > 30:
        print("You're at risk because of a high BMI!")

Much better. Apparently this function determines a person at risk if his BMI is over 30 and he/she is over 30 years old. Our function has doubled in length but at least things are clear now.

So that's it? 

Well not exactly. Our function definition may be clear now but remember that we are still calling our function by passing in a tuple. Everywhere this data structure is in use you will have to write quite expressive code or add substantial comments to make your intent clear.

Introducing namedtuples

Using namedtuples we can refer to the elements of a tuple by field name. In the Body Mass Index example above we can then write things like bmi = person_data.weight / person_data.height ** 2

The namedtuple  is found in the collections  module and you use it like this

from collections import namedtuple

Person = namedtuple('Person', ['name', 'age', 'weight', 'height'])

me = Person('Michael', 30, 78, 1.8)
bmi = me.weight / me.height ** 2

Let's run through the example above. After importing namedtuple  from the collections  module we create our Person  namedtuple. The first parameter is used to name our namedtuple, the second parameter is list of field names to add to our namedtuple.

The resulting variable, in this case Person , is actually a class that is created by namedtuple. You can see that on line 5 we create an instance of the Person class. And here we have the secret behind the namedtuple. What we are getting is actually a class we can instantiate, and refer to the fields by name as with any class, but this class is also a drop-in replacement for a tuple. So any code that expects a tuple can take in an instance of a namedtuple created class:

>>> me
Person(name='Michael', age=30, weight=78, height=1.8)
>>> me[0]
>>> me[3]
>>> me[4]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
IndexError: tuple index out of range
>>> 'Michael' in me


If you find yourself using tuples to group related data and pass them around in your code, consider defining a namedtuple to improve the readability of your code. A lightweight alternative to defining a complete class, namedtuples can be gradually integrated in your existing codebase thanks to their tuple compatibility.

More information

Read all about Python namedtuples on the official collections documentation.