This article was orginally published on python-programming.com 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...
When passing along or returning tuples in your code, things usually go like this:
def bmi_risk(person_data): bmi = (person_data / person_data**2) if person_data > 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?
def bmi_risk(person_data): age = person_data height = person_data weight = person_data 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.
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 print(bmi)
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 'Michael' >>> me 1.8 >>> me Traceback (most recent call last): File "<stdin>", line 1, in <module> IndexError: tuple index out of range >>> 'Michael' in me True
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.
Read all about Python namedtuples on the official collections documentation.