Find us on GitHub

# Python: Tuples

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…

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.