Execute Program

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'Pass Icon
  • As with lists, accessing a tuple index that doesn't exist raises an exception.

  • (You can type error when 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 rangePass Icon
  • 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:
    2Pass Icon
  • 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 = 3
    y = 2
    z = 4
    treasure_coordinates = x, y, z
    treasure_coordinates[1]
    Result:
    2Pass Icon
  • 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_2
    Result:
    TruePass Icon
  • 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:
    2Pass Icon
  • Like lists, tuples support the in operator, which returns True if the tuple contains the value.

  • >
    my_data = (1, 10, 100)
    100 in my_data
    Result:
    TruePass Icon
  • 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 a TypeError.

  • >
    tennis_score = (15, 15)
    tennis_score[0] = 30
    tennis_score
    Result:
    TypeError: 'tuple' object does not support item assignmentPass Icon
  • Because tuples are immutable, they don't have equivalents of the list methods that modify values, like .pop or .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")
    visitors
    Result:
    AttributeError: 'tuple' object has no attribute 'append'Pass Icon
  • Take a look at the specific error message there. It may be surprising: why is it an AttributeError instead of something like NoMethodError? 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_2 returns a new tuple with all elements of tuple_1 followed by all elements of tuple_2.

  • >
    (1, 2) + (3, 4)
    Result:
    (1, 2, 3, 4)Pass Icon
  • If we try to add a tuple and a list, we get a TypeError exception.

  • >
    (1, 2) + [3, 4]
    Result:
    TypeError: can only concatenate tuple (not "list") to tuplePass Icon
  • >
    [1, 2] + (3, 4)
    Result:
    TypeError: can only concatenate list (not "tuple") to listPass Icon
  • 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)Pass Icon
  • >
    some_tuple = (1, 2)
    list(some_tuple) + [3, 4]
    Result:
    [1, 2, 3, 4]Pass Icon
  • 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")
    cats
    Result:
  • 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 = 3
    bettys_cat = (name, age)
    bettys_cat
    Result:
    ('Keanu', 3)Pass Icon
  • 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:
    1Pass Icon
  • The comma is necessary because the expression (12) evaluates to the number 12!

  • >
    not_a_tuple = (12)
    not_a_tuple
    Result:
    12Pass Icon
  • >
    tiny_tuple = 12,
    tiny_tuple[0]
    Result:
    12Pass Icon
  • 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 = 12
    y = 24,
    x + y
    Result:
  • 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!