Python for Programmers: Tuples
Welcome to the Tuples lesson!
This lesson is shown as static text below. However, it's designed to be used interactively. Click the button below to start!
We saw lists in an earlier lesson. They're ordered collections of values, with integer indexes starting at 0. They can contain mixed types (for example, both strings and numbers).
Python also supports tuples. Like lists, they're ordered collections, start at index 0, and can contain mixed types. In this lesson, we'll explore how tuples work, then discuss why Python supports both lists and tuples.
Literal tuples are defined with (parens) instead of [square brackets].
>
hand_equipment = ("sword", "shield")hand_equipment[0]Result:
- Note: this code example reuses elements (variables, etc.) defined in earlier examples.
>
hand_equipment[1]Result:
'shield'
As with lists, accessing a tuple index that doesn't exist raises an exception.
(You can type
errorwhen a code example will cause an error.)- Note: this code example reuses elements (variables, etc.) defined in earlier examples.
>
hand_equipment[2]Result:
IndexError: tuple index out of range
Tuples can have any number of elements. For example, we can use them to represent the three coordinates in 3D space.
>
treasure_coordinates = (3, 2, 4)treasure_coordinates[1]Result:
2
We normally put parentheses around the tuple for clarity, but in some situations the parentheses are optional. However, the commas are mandatory: the comma is what makes it a tuple!
>
x = 3y = 2z = 4treasure_coordinates = x, y, ztreasure_coordinates[1]Result:
2
We recommend always including the parentheses for clarity, even when they're not required.
Python allows trailing commas when writing a tuple. They don't affect the tuple's value.
>
tuple_1 = (3, 2, 4)tuple_2 = (3, 2, 4,)tuple_1 == tuple_2Result:
True
Opinions on trailing commas vary, and their use is usually decided on a per-team basis. Generally speaking, trailing commas are only used for multi-line tuples, but not for single-line tuples.
>
tall_tuple = (3,2,4,)tall_tuple[1]Result:
2
Like lists, tuples support the
inoperator, which returnsTrueif the tuple contains the value.>
my_data = (1, 10, 100)100 in my_dataResult:
True
Unlike lists, tuples are immutable. We can change lists after they're created, but we can't change a tuple. If we try to reassign an element of a tuple, like
my_tuple[1] = new_value, we'll get aTypeError.>
tennis_score = (15, 15)tennis_score[0] = 30tennis_scoreResult:
TypeError: 'tuple' object does not support item assignment
Because tuples are immutable, they don't have equivalents of the list methods that modify values, like
.popor.append. Trying to call those methods raises an exception, just like any other situation where we try to call a method that doesn't exist.>
visitors = ("Cindy", "Dalili")visitors.append("Amir")visitorsResult:
AttributeError: 'tuple' object has no attribute 'append'
Take a look at the specific error message there. It may be surprising: why is it an
AttributeErrorinstead of something likeNoMethodError? The answer is that, at a deep level, Python methods are the same thing as attributes (which are called "instance variables" or "properties" in other languages). We'll explore attributes in a future lesson.Although we can't modify tuples, we can build new tuples out of existing ones.
tuple_1 + tuple_2returns a new tuple with all elements oftuple_1followed by all elements oftuple_2.>
(1, 2) + (3, 4)Result:
(1, 2, 3, 4)
If we try to add a tuple and a list, we get a
TypeErrorexception.>
(1, 2) + [3, 4]Result:
TypeError: can only concatenate tuple (not "list") to tuple
>
[1, 2] + (3, 4)Result:
TypeError: can only concatenate list (not "tuple") to list
This is another place where Python is more careful about data types than many other popular dynamic languages like JavaScript, PHP, or Lua. There are some situations where it makes sense to combine a tuple with a list, but they're uncommon. If we do this accidentally, it's better to get an exception so we find out about it sooner rather than later.
If we really want to combine a tuple with a list, we can convert the tuple into a list, or convert the list into a tuple. Either way works, depending on what data type we want at the end.
>
some_list = [3, 4](1, 2) + tuple(some_list)Result:
(1, 2, 3, 4)
>
some_tuple = (1, 2)list(some_tuple) + [3, 4]Result:
[1, 2, 3, 4]
Here are some rules of thumb for choosing between the two data structures.
If we need to replace elements, add elements over time, or remove elements, we have to use a list. But if the elements shouldn't ever change, tuples are better because they prevent accidental changes.
If we can describe our data as "a sequence of many X", then a list probably makes more sense. For example, when storing the names of several cats, a list is more idiomatic than a tuple.
>
cat_1 = "Keanu"cat_2 = "Ms. Fluff"cats = [cat_1, cat_2]cats.append("Wilford")catsResult:
If we're storing a single cat's name along with its age, then a tuple probably makes more sense. There are always exactly two elements (name and age), so it's not "a sequence of many X". Rather, it's "a fixed set of facts about the cat".
>
name = "Keanu"age = 3bettys_cat = (name, age)bettys_catResult:
('Keanu', 3)We'll see more reasons to use tuples over lists in future lessons.
There's one important syntax oddity to note for tuples. While a trailing comma is optional for multi-element tuples, a single-element tuple must have a trailing comma.
>
tiny_tuple = (12, )len(tiny_tuple)Result:
1
The comma is necessary because the expression
(12)evaluates to the number12!>
not_a_tuple = (12)not_a_tupleResult:
12
>
tiny_tuple = 12,tiny_tuple[0]Result:
12
This oddity can lead to bugs. If we forget the trailing comma in a one-element tuple, the expression is no longer a tuple. Conversely, if we leave a stray comma at the end of a line, now it's accidentally a tuple! Here's an example of that kind of mistake:
>
x = 12y = 24,x + yResult:
In that simple example, the exception happened on the very next line. But in a real system, the exception might happen in a different module from where the tuple was created, which can be difficult to debug!