Find us on GitHub

Teaching basic lab skills
for research computing

Python: Tuples

Python/Tuples at YouTube

Hello, and welcome to the eleventh episode of the Software Carpentry lecture on Python. This episode introduces Python's "other" kind of sequence data type.

As we saw a few episodes ago, a list is a mutable sequence of values, which can be of any type.

A tuple is simply an immutable sequence of heterogeneous values.

I.e., a list whose entries can't be changed after its creation.

At first or even second glance, it may seem strange to have tuples in the language—why provide a less general kind of collection?

The full explanation will have to wait for the lecture on sets and dictionaries.

But tuples allow us to do a few useful things even before we get that far.

In Python, we create tuples using parentheses () instead of square brackets [].

We still index them with square brackets, though, because everything in Python that's indexed uses square brackets.

For example, here's a tuple containing the first four prime numbers. Just as with a list, primes[0] is its first element, and primes[-1] is its last.

The empty tuple is written as, well, empty parentheses, and has a length of 0.

If we want to create a tuple of just one value, though, we have to put a comma after that value and before the closing parenthesis. It looks a little odd…

…but otherwise, (5) would be ambiguous: mathematically, it's the same as (2+3).

This trailing comma is easy to forget, and is one of Python's few syntactic warts.

The good news is, we don't need the parentheses if it's clear from context that we're constructing a tuple.

For example, we can create our tuple of primes just by putting commas between the four values, as shown here.

The neat thing is, if we put a tuple of variables on the left side of an assignment, we can assign multiple values at once.

For example, this statement sets the values of left, middle, and right all in one go.

We can check that it worked by printing those variables out.

But remember: with great power comes great responsibility. Initializing thirty-odd variables at once this way is probably not going to make your programs more readable…

This same trick—tuple-to-tuple assignment—allows functions to return several values at once.

For example, here's a function called bounds that returns the lowest and highest elements of its parameter values at the same time.

Sure enough, it returns a two-element tuple.

And if we assign that tuple to a pair of variables, Python unpacks the two values and copies them into the variables in the right order.

Functions sometimes use this technique to return a success or failure flag along with their actual result, which is only valid if the flag indicated success.

Here, for example, read_if_available returns either True and a list of data values, or False and an empty list.

Its caller can capture both values at once, then check the first to learn whether the second is meaningful or not.

We'll meet a better way to do this kind of thing in the lecture on testing.

Multiple-valued assignment is also a quick way to swap variables' values.

Let's initialize left and right to 0 and 10 respectively.

And then assign left and right to right and left.

Sure enough, when we're done, Python has swapped their values.

There's no magic here: behind the scenes, Python is creating a temporary variable to hold onto one value while it copies the other.

If we draw what's in memory at the start, left refers to 0 and right refers to 10.

Python creates a temporary variable (probably not actually named _tmp_, but that doesn't matter)…

…and copies left's pointer to 0 into it.

It then copies right into left

_tmp_ into right

…and throws away the temporary variable, all behind the programmer's back.

Multi-valued assignment is also a quick and easy way to unpack the elements of lists.

If colors holds the strings 'yellow', 'magenta', and 'lavender'

…and we assign colors to a trio of variables called left, middle, and right

…then sure enough, left has been assigned 'yellow', middle has been assigned 'magenta', and right has been assigned 'lavender'.

This only works if the number of variables on the left to "catch" values is the same as the number of values in the list.

Unpacking is often used to simplify loops.

For example, suppose we have a list of pairs of numbers.

We could add the values in each pair like this…

…but it's not particularly readable.

Here's a better way: the for loop gives us the pairs one by one, and when we assign each pair to the two variables low and high, Python automatically unpacks the pair's values for us.

We'll use this technique a lot in the lectures that follow.

To make life even easier, Python has a built-in function called enumerate that takes a sequence (i.e., a list, tuple, or string) as input, and produces (index, value) pairs—just right for looping.

This bit of code uses enumerate to loop through our list of colors, printing each value and its index.

The output is pretty much what you'd expect.

And this is tidier and more efficient than the range(len(list)) idiom shown a few episodes ago.

Thank you.