South Plantation High School logo
South Plantation High School · Procedural Programming with Python

Tuples

Indexing & slicing · Immutability · Tuples vs lists · Nesting · Lesson review

Review the lesson slides, then complete the assignment at the bottom of this page. Your assignment work is saved in this browser on this computer. When you check a task, your name, period, and which tasks are complete are shared with your teacher (your code is not). When you finish, print it or save it as a PDF to turn in.
1 / 17
Lesson Review

Tuples

(3, 4)point[0]days[1:4]x, y = point[("Ava", 92)]

A list's locked cousin: an ordered group of values that cannot be changed after it is made.

By the end of this lesson you will be able to:

  • Construct tuples and access their elements with indexing and slicing.
  • Explain what it means that tuples are immutable, and why that is useful.
  • Decide when to use a tuple and when to use a list.
  • Nest lists inside tuples and tuples inside lists.
How to use this page: Use Next and Back (or the arrow keys). Run the editors, try the index and slice tools, sort situations into "tuple" or "list," and use the Memory Viewer to see what is locked and what is not.

Words you will hear today

WordWhat it meansExample
tupleAn ordered, unchangeable group of values(3, 4)
elementOne value inside the tuple3
immutableCannot be changed after it is createdtuples, strings, numbers
packingPutting several values into one tuplet = 1, 2
unpackingSplitting a tuple into separate variablesx, y = t
recordA group of related facts about one thing("Ava", 15, "Period 3")
  • Create, index, slice, immutability, tuple vs list, nesting.
  • Tuple, immutable, packing, unpacking, record.

You already know lists. Tuples look almost the same and are indexed and sliced the same way. The big difference is that once a tuple is made, it cannot be changed. Today we learn how to build them, why being unchangeable is actually a feature, and how tuples and lists work together.

Creating Tuples

What is a tuple?

The Python tutorial: "A tuple consists of a number of values separated by commas."

point = (3, 4)                  # x and y
rgb = (255, 107, 53)            # a color
info = ("Ava", 15, 3.8, True)   # mixed types are fine
print(type(point))              # <class 'tuple'>
  • Tuples use parentheses ( ); lists use square brackets [ ].
  • Python always prints a tuple with parentheses.
The comma is what matters. The docs: "Note that it is actually the comma which makes a tuple, not the parentheses." So point = 3, 4 also makes a tuple. Writing the parentheses is still clearer.

Pick a line and run it. Watch the type and length.

When a tuple is the natural choice

A tuple is like a form with a fixed set of boxes. Each position has a meaning that never changes:

  • point = (3, 4): position 0 is always x, position 1 is always y.
  • rgb = (255, 107, 53): red, green, blue, always in that order.
  • birthday = (2010, 5, 17): year, month, day.

You would never "append" a fourth number to a color or a fifth part to a date. The size is part of what the data means, and that is a sign a tuple fits.

  • Tuple = values separated by commas, usually in ( ).
  • The comma makes the tuple.
  • Tuples fit data with a fixed number of parts, each with a meaning.

A tuple is a group of values separated by commas. We usually wrap them in parentheses so they are easy to see. A tuple is great for a small group of values that belong together, like the x and y of a point or the red, green, and blue parts of a color.

Creating Tuples

Special cases: empty, one item, and tuple()

The tutorial: "Empty tuples are constructed by an empty pair of parentheses; a tuple with one item is constructed by following a value with a comma (it is not sufficient to enclose a single value in parentheses). Ugly, but effective."

CodeResultType
()()tuple (empty)
(5,)(5,)tuple with one item
(5)5int! Just a number in parentheses
tuple([1, 2, 3])(1, 2, 3)tuple from a list
tuple("hey")('h', 'e', 'y')tuple from a string
tuple(range(4))(0, 1, 2, 3)tuple from a range
Watch the one-item tuple. (5) is the number 5, because parentheses are also used for math, like (2 + 3) * 4. The trailing comma in (5,) is what makes it a tuple.

Why the comma rule exists

Parentheses already have a job in Python: grouping math, like (2 + 3) * 4. So (5) must mean "the number 5, grouped." Python needed some other way to say "a tuple with one thing," and the trailing comma is it.

Check yourself: type((5)) is int, but type((5,)) is tuple. If a one-item tuple behaves like a number, look for a missing comma.

When would you have an empty or one-item tuple?

Usually when a tuple is built by a program, not typed by hand: for example, a search that finds zero or one matching result, or t + (4,) to add a single item to an existing tuple.

  • () empty. (5,) one item. (5) is an int.
  • tuple(iterable) converts.
  • (5) is an int; (5,) is a tuple.

Two special cases trip people up. An empty tuple is just a pair of parentheses. A tuple with one item needs a comma after the item. Without the comma, Python treats the parentheses as math grouping, so (5) is simply the number 5. The tuple function converts a list, string, or range into a tuple.

Indexing & Slicing

Indexing a tuple

Indexing works exactly like it does for lists: positive indexes from 0 at the front, negative indexes from -1 at the back.

days = ("Mon", "Tue", "Wed", "Thu", "Fri")
print(days[0])     # Mon
print(days[2])     # Wed
print(days[-1])    # Fri
print(len(days))   # 5
print(days[5])     # IndexError: tuple index out of range

Change the index and run it.

Reading records by index

student = ("Ava", 15, "Period 3")
name = student[0]
age = student[1]
print(name, "is", age)    # Ava is 15

Indexing reads a tuple; it never changes it. That is why every indexing trick from lists (negative indexes, len(), a variable as the index) works on tuples without any problem.

Tip: when a tuple holds a record, unpacking (slide 9) is often clearer than indexes, because name says more than student[0].

  • Same indexing rules as lists.
  • Out of range: IndexError: tuple index out of range.
  • Indexing only reads, so it works on tuples.

Good news: everything you learned about indexing lists works on tuples. Zero is the first item, negative one is the last, and an index that is too big gives an IndexError that says tuple instead of list. Click the boxes to see both indexes of each day.

Indexing & Slicing

Slicing a tuple

Slicing also works like lists, and a slice of a tuple is a new tuple.

SliceResult
days[1:4]('Tue', 'Wed', 'Thu')
days[:2]('Mon', 'Tue')
days[-2:]('Thu', 'Fri')
days[::2]('Mon', 'Wed', 'Fri')
days[::-1]('Fri', 'Thu', 'Wed', 'Tue', 'Mon')
Remember: start is in, stop is out. Slicing never changes the original tuple; it builds a new one. That is why slicing is allowed on an unchangeable tuple.

Pick a start, stop, and step. The highlighted boxes are the new tuple.

The result keeps the type

Slicing a tuple gives a tuple, slicing a list gives a list, and slicing a string gives a string. Even a slice with one item is still a tuple: days[0:1] is ('Mon',), not 'Mon'.

Out-of-range slices are still safe: days[3:100] gives ('Thu', 'Fri') with no error, and days[10:] gives the empty tuple ().

  • A tuple slice is a new tuple.
  • Start included, stop excluded.
  • A one-item slice is still a tuple, like ('Mon',).

Slicing a tuple gives you a new, smaller tuple. The rules are the same as for lists: start is included, stop is excluded, and a step of negative one reverses. Slicing is fine on a tuple because it does not change the original. It reads it and builds something new.

Immutability

Tuples are immutable (unchangeable)

Immutable means that once a tuple is created, its items cannot be replaced, added, or removed. The tutorial: "It is not possible to assign to the individual items of a tuple."

Try to...CodePython 3.13 says
replace an itemt[0] = 99TypeError: 'tuple' object does not support item assignment
delete an itemdel t[0]TypeError: 'tuple' object doesn't support item deletion
add an itemt.append(4)AttributeError: 'tuple' object has no attribute 'append'
sort in placet.sort()AttributeError: 'tuple' object has no attribute 'sort'
What you can do: build a new tuple and point the name at it: t = t + (4,). The old tuple is not changed; the name t just moves to the new one.

What t = t + (4,) really does

  1. t + (4,) builds a brand new tuple (1, 2, 3, 4).
  2. t = ... moves the name t to that new tuple.
  3. The old (1, 2, 3) was never touched. If another name still points to it, that name still sees (1, 2, 3).

So the variable can change what it refers to, but the tuple itself never changes. That is the whole meaning of immutable.

Notice the error types: trying to assign or delete gives a TypeError. Trying a list method gives an AttributeError, which means "tuples don't have a tool by that name."

  • No item assignment, no del, no append, no sort.
  • t = t + (4,) builds a new tuple.
  • The name can move to a new tuple; the old tuple never changes.

Here is the defining rule of tuples: you cannot change them. No replacing, no deleting, and no list methods like append or sort. You can make a brand new tuple, though, and reuse the same name for it. Try each option in the editor and read the error messages.

Immutability

Why would we want something we cannot change?

The Python FAQ explains how the two types are meant to be used:

"Tuples can be thought of as being similar to Pascal records or C structs; they're small collections of related data which may be of different types which are operated on as a group. For example, a Cartesian coordinate is appropriately represented as a tuple of two or three numbers."
"Lists, on the other hand, are more like arrays in other languages. They tend to hold a varying number of objects all of which have the same type and which are operated on one-by-one."

Reasons to use a tuple

  • Safety: data that should never change (like the days of the week) cannot be changed by accident somewhere else in your program.
  • Meaning: a tuple tells the reader "this is one fixed record," like a point (x, y) or a color (r, g, b).
  • Dictionary keys: the FAQ notes that "only immutable elements can be used as dictionary keys, and hence only tuples and not lists can be used as keys." (Dictionaries come later in the course.)
  • Unpacking: tuples are easy to split into separate variables (slide 9).

Immutability prevents a whole kind of bug

Remember from the lists lesson that b = a gives one list two names, and a change through one name shows up in the other. With a tuple, that can never surprise you, because nothing can change it. You can share a tuple anywhere in your program and be sure it stays the same.

A quick decision test

  • "Is this one thing described by several values?" (a point, a date, a student record) → tuple
  • "Is this a collection of many similar things that may grow or be sorted?" (all the scores, all the students) → list
  • Tuple: a fixed record of related values. List: a growing collection of similar items.
  • Immutability = safety + meaning + dictionary keys.
  • One thing with several parts: tuple. Many similar things: list.

Why limit ourselves? Because some data should not change. A point on a map has exactly an x and a y. A color has exactly red, green, and blue. Making these tuples protects them from accidental changes, and it tells anyone reading your code that this is one fixed record, not a list that will grow.

Tuple Tools

What you can do with a tuple

Anything that only reads a tuple works. Anything that would change it does not.

Works on tuplesExample with t = (5, 9, 2, 5, 7)
len, inlen(t) is 5, 9 in t is True
.count(), .index()the only two tuple methods: t.count(5) is 2
min, max, summin(t) is 2, sum(t) is 28
sorted()gives a list: [2, 5, 5, 7, 9]
+ and *make new tuples: t + (1,), (0,) * 3
for loopsfor n in t: just like a list

Notice what sorted() gives back

sorted() works on any sequence, but it always returns a list, because it has to build something new in a different order. If you need a sorted tuple, wrap it: tuple(sorted(t)) gives (2, 5, 5, 7, 9).

Tuples can be compared

Python compares tuples one element at a time, left to right, like alphabetizing words letter by letter. (1, 5) < (2, 0) is True because 1 < 2 decides it right away. Only when the first elements tie does Python look at the second.

  • Reading tools work. Changing tools do not.
  • count and index are the only tuple methods.
  • sorted() returns a list; tuple(sorted(t)) for a tuple.
  • Tuples compare element by element.

The rule of thumb: if it only looks at the data, it works on a tuple. Length, membership, counting, finding, min, max, sum, loops, slicing: all fine. Notice that sorted gives back a list, because it builds a new sorted collection. If you need it as a tuple again, wrap it with tuple.

Tuple Tools

Packing and unpacking

The tutorial: t = 12345, 54321, 'hello!' "is an example of tuple packing." The reverse, x, y, z = t, "is called, appropriately enough, sequence unpacking."

point = (3, 4)      # packing
x, y = point        # unpacking: x is 3, y is 4

a, b = 1, 2
a, b = b, a         # swap! a is 2, b is 1

q, r = divmod(17, 5)   # divmod gives a tuple: (3, 2)
The tutorial: "Sequence unpacking requires that there are as many variables on the left side of the equals sign as there are elements in the sequence." Otherwise: ValueError: too many values to unpack (expected 2) or not enough values to unpack.

How the swap works

a, b = b, a looks like magic, but it follows the normal rule: the right side runs first.

  1. b, a packs the current values into a tuple: (2, 1).
  2. Then the tuple is unpacked: a gets 2 and b gets 1.

In many other languages you need a third "temp" variable to swap. Python's packing and unpacking do it in one line.

Collecting the rest with *

If you only want the first item and everything else together, put a * on one name: first, *rest = (1, 2, 3) makes first 1 and rest the list [2, 3].

  • Packing: commas build a tuple. Unpacking: names = tuple.
  • Counts must match.
  • Swap: the right side is packed first, then unpacked.
  • first, *rest = t collects the rest in a list.

Packing means putting several values into one tuple. Unpacking means taking them back out into separate variables in one line. The number of names on the left must match the number of items. The swap trick, a comma b equals b comma a, is a favorite: Python packs the right side into a tuple first, then unpacks it.

Tuples vs Lists

Tuples versus lists

TupleList
Brackets(1, 2, 3)[1, 2, 3]
Change items?No (immutable)Yes (mutable)
Methodscount, indexmany: append, sort, ...
Indexing, slicing, loopsYesYes
Typical usea fixed record of related valuesa collection that grows, shrinks, or gets sorted
Dictionary key?YesNo

The tutorial sums it up: tuples "usually contain a heterogeneous sequence of elements," while list "elements are usually homogeneous and are accessed by iterating over the list." (Heterogeneous means different kinds; homogeneous means the same kind.)

Tuple or list? Choose for each situation, then click Check.

Examples to sort out

DataBest choiceWhy
A player's (x, y) position on a maptuplealways exactly two numbers with fixed meanings
The items in a shopping cartlistitems get added and removed
The months of the yeartuplefixed and should never change
High scores, kept in orderlistnew scores are added and the list is sorted
  • Will it change? List. Is it one fixed record? Tuple.

Here is a quick test. Ask: will this data need to change while the program runs? If yes, use a list. If it is one fixed record, like a point, a color, or a date, use a tuple. Try the chooser and read the reason for each answer.

Tuples vs Lists

Converting between tuples and lists

  • list(t) makes a new list from a tuple.
  • tuple(lst) makes a new tuple from a list.

To "change" a tuple: convert it to a list, change the list, then convert back. You end up with a new tuple.

days = ("Mon", "Tue", "Wed")
temp = list(days)        # ['Mon', 'Tue', 'Wed']
temp[0] = "Sun"
temp.append("Thu")
days = tuple(temp)       # ('Sun', 'Tue', 'Wed', 'Thu')
If you find yourself doing this a lot, the data probably should have been a list in the first place.

Step through and watch days and temp in the Variables panel.

Why the round trip works

list(days) does not change the tuple. It reads every item and puts them into a new list. You change that list freely, then tuple(temp) reads the list and builds a new tuple. At no point is a tuple modified.

A shortcut for adding: to add just one or two items, you do not need to convert. days = days + ("Thu",) does it directly.

  • list(t) and tuple(lst) convert.
  • Convert, change, convert back gives a new tuple.
  • list(t) and tuple(lst) each build something new.

Sometimes you have a tuple but need to make changes. The pattern is: convert to a list, make your changes, and convert back to a tuple. Remember that this creates a new tuple; the original was never changed.

Nesting

Tuples inside a list

A very common pattern: a list of records, where each record is a tuple.

students = [("Ava", 92), ("Ben", 85)]
students.append(("Cy", 77))     # OK: the list can grow
print(students[1])              # ('Ben', 85)
print(students[1][0])           # Ben
for name, score in students:    # unpack each tuple
    print(name, score)
CodeAllowed?
students.append(("Di", 90))Yes, the list changes
students[0] = ("Ava", 95)Yes, the list gets a new tuple
students[0][1] = 95No: TypeError: 'tuple' object does not support item assignment

Working with a list of records

Because each record is a tuple and the collection is a list, you get the best of both: the list can grow and be sorted, and each record stays intact.

students = [("Ava", 92), ("Ben", 85), ("Cy", 77)]
total = 0
for name, score in students:
    total += score
print("Average:", total / len(students))   # Average: 84.66...

Sorting records: sorted(students) sorts by the first element (the name), because tuples compare left to right. To change a score, replace the whole record: students[0] = ("Ava", 95).

  • The outer list can change. Each tuple inside cannot.
  • for name, score in records: unpacks each tuple.
  • A list of tuples: the list changes, each record stays intact.

Putting tuples inside a list gives you the best of both. The list can grow, shrink, and be sorted, while each record inside stays locked together, so a name can never get separated from its score. To update a record, replace the whole tuple.

Nesting

Lists inside a tuple

The tutorial: "it is possible to create tuples which contain mutable objects, such as lists."

student = ("Ava", [90, 85])
student[1].append(77)       # OK! the LIST changes
print(student)              # ('Ava', [90, 85, 77])
student[1] = [100]          # TypeError!
What exactly is locked? The tuple holds a fixed set of references: "slot 0 is this string, slot 1 is this list." You cannot change which list is in slot 1. But the list itself is still a normal, changeable list.
So a tuple is only "fully frozen" when everything inside it is also immutable (numbers, strings, other tuples).

Think of slots and arrows

A tuple is a row of locked slots. Each slot holds an arrow pointing to a value. The arrows can never be moved, but if an arrow points to a list, you can still walk down the arrow and change that list.

  • student[1].append(77) follows the arrow in slot 1 and changes the list: allowed.
  • student[1] = [100] tries to move the arrow in slot 1 to a different list: TypeError.

One consequence: a tuple containing a list cannot be a dictionary key. Python checks everything inside, and a list inside makes the whole tuple "unhashable."

  • The tuple's slots are fixed. A list in a slot can still change.
  • Slots are locked; a list in a slot can still change.

This one surprises people. A tuple can hold a list, and that list can still change. The tuple only promises that its slots will always point to the same objects. Slot 1 will always be that same list, but nothing stops the list from growing. Try each option in the editor.

Practice

Memory Viewer: tuples and lists

Pick an example and click Step. Tuples are labeled "locked" and drawn with a dashed border; lists are labeled "changeable." Arrow tags show which object a name or slot points to. Nothing is recorded.

What to look for

  • Every time a line uses + with a tuple, watch for a new tuple box appearing, while the old one stays the same.
  • When a list sits inside a tuple, changing the list changes the drawing inside the list box, but the tuple's arrows stay where they were.
  • Two names with the same tag share one object. With a tuple that is always safe; with a list, a change shows up for both names.
  • Locked tuple, but the list it points to can change.

Step through each example. In the first one, watch t move to a brand new tuple while u keeps the old one. In the list inside a tuple example, notice that the tuple never changes, but the list it points to does.

Debugging

Common mistakes

MistakeCodeWhat happens (Python 3.13)Fix
One-item tuple without a commat = (5)No error. t is the int 5t = (5,)
Changing an itemt[0] = 9TypeError: 'tuple' object does not support item assignmentMake a new tuple, or use a list
Using a list methodt.append(4)AttributeError: 'tuple' object has no attribute 'append't = t + (4,)
Sorting in placet.sort()AttributeError: 'tuple' object has no attribute 'sort'sorted(t) (gives a list)
Adding a list to a tuplet + [3]TypeError: can only concatenate tuple (not "list") to tuplet + (3,)
Wrong number of namesx, y = (1, 2, 3)ValueError: too many values to unpack (expected 2)One name per item
Index too bigt[5] on 3 itemsIndexError: tuple index out of ranget[-1] for the last item
Finding a missing itemt.index(9)ValueError: tuple.index(x): x not in tupleif 9 in t: first
Changing a record in a liststudents[0][1] = 95TypeError: 'tuple' object does not support item assignmentstudents[0] = ("Ava", 95)

Try these at the prompt:

  • t = (1, 2, 3)
  • t[1:]
  • t[0] = 9
  • type((5))
  • type((5,))
  • x, y, z = t
  • t + (4,)
  • t

Fixing tuple errors

  • TypeError ... item assignment / deletion: you tried to change a tuple. Build a new tuple, or ask yourself whether this data should be a list.
  • AttributeError ... has no attribute: you used a list method. Tuples only have count and index.
  • ValueError ... unpack: count the names on the left and the items on the right; they must match.
  • A "tuple" acting like a number: you are missing the comma in a one-item tuple.
  • The (5) mistake gives no error; the others name the problem.
  • TypeError: tried to change. AttributeError: list method. ValueError: unpack count.

Most tuple mistakes come from treating a tuple like a list. If you see "does not support item assignment" or "has no attribute append," either build a new tuple or ask yourself whether this data should be a list instead.

Practice

Check yourself

Choose an answer, then click Check. This is practice only. Nothing is graded or recorded.

For each question, ask:
  • Is this reading the tuple (indexing, slicing, len, in, count) or changing it?
  • Is there a comma? (5) vs. (5,).
  • For nested data: is the thing being changed the tuple's slot, or a list inside it?
  • Reading works; changing does not.

For each question, ask: does this code only read the tuple, or does it try to change it? Reading always works the same as with lists. Changing a tuple's slots never works.

Summary

Cheat sheet

Create and read

point = (3, 4)
single = (5,)
empty = ()
t = tuple([1, 2, 3])
point[0]      # 3
point[-1]     # 4
t[1:]         # (2, 3)
x, y = point  # unpack

Immutable

  • No t[0] = ..., no del, no append or sort
  • Only methods: count, index
  • Make a new tuple: t = t + (4,)
  • Convert: list(t), tuple(lst)
  • Use for fixed records: points, colors, dates

Nesting

# tuples in a list
students = [("Ava", 92), ("Ben", 85)]
students[1][0]       # 'Ben'
for name, score in students:
    print(name, score)

# a list in a tuple
rec = ("Ava", [90, 85])
rec[1].append(77)    # OK

Remember:

  • The comma makes a tuple: (5,) is a tuple, (5) is not
  • Indexing and slicing work exactly like lists; a slice of a tuple is a tuple
  • Will the data change? Use a list. Is it one fixed record? Use a tuple
  • A tuple's slots are locked, but a list inside a tuple can still change

Key words to know

tuple · element · immutable / mutable · packing · unpacking · swap · record · heterogeneous / homogeneous · nesting · dictionary key

  • Create, read, immutable, choose, nest.
  • Know the key words: immutable, packing, unpacking, record.

Let's wrap up. A tuple is an ordered group of values made with commas, usually in parentheses. You read it exactly like a list, but you cannot change it. Use tuples for fixed records and lists for collections that change, and combine them: a list of tuples is one of the most useful structures in Python.