Tuples
By the Syncfusion DevTutorials team · Last updated
Immutable ordered records: the trailing-comma trap, slicing, rebuilding instead of changing, packing and unpacking, and the two tuple methods.
Think about a printed exam certificate.
It says the name, the subject and the mark. Once it is printed, nobody changes it. If something is wrong you print a new one — you do not scratch out a number and write another.
A list is a whiteboard. A tuple is a printed certificate: the same kind of contents, fixed once written.
Here is that idea in action — a record that refuses to be changed:
A record that cannot be changed
result = ("Asha", "Maths", 78)
print(result)
print(result[0])
print(len(result))
try:
result[2] = 90
except TypeError as error:
print("Refused:", error)
A tuple holds many values in order, like a list, but it cannot be changed after it is made.
What You Will Learn
In this lesson, you will learn:
- How to make a tuple, including the two cases that trip everyone up
- Why immutability is useful rather than a limitation
- When to choose a tuple over a list
- How to reach items, including inside nested tuples
- How to "change" a tuple, and what that really means
- Packing and unpacking, which you have already used without knowing it
By the end of this lesson, you will be able to create tuples, explain why their fixed nature is useful, choose between a tuple and a list, reach items with indexes and slices, build a new tuple in place of a changed one, and pack and unpack values.
Python Tuples
Introduction to Tuples
A tuple is an ordered collection, like a list, that cannot be changed once created.
Creating Tuples
There are several ways to make a tuple, and one detail in them matters more than the rest:
Several ways to make a tuple
a = ("Asha", "Maths", 78)
b = "Asha", "Maths", 78
c = tuple(["Asha", "Maths", 78])
d = tuple("Asha")
print(a)
print(b)
print(c)
print(d)
print(a == b == c)
It is the commas that make a tuple, not the brackets. The brackets are usually there for clarity, and sometimes required to avoid ambiguity.
Empty Tuples
An empty tuple is straightforward — brackets with nothing inside:
An empty tuple
empty = ()
also_empty = tuple()
print(empty, also_empty, len(empty))
print(empty == also_empty)
Single-Element Tuples
This is the one that catches everybody.
A tuple of one needs a trailing comma
one = (78,)
not_a_tuple = (78)
print(one, type(one).__name__)
print(not_a_tuple, type(not_a_tuple).__name__)
(78) is just 78 in brackets — brackets used for grouping, as in (2 + 3) * 4. The comma is what makes it a tuple.
Where the missing comma bites
single = (78)
print("Length of (78,):", len((78,)))
try:
print(len(single))
except TypeError as error:
print("Refused:", error)
Tuple Characteristics
Most of a tuple's characteristics are the same as a list's, with one important exception:
| Characteristic | What it means |
|---|---|
| Ordered | items keep the order you put them in |
| Indexed | the first item is at 0 |
| Immutable | it cannot be changed after it is made |
| Duplicates allowed | the same value can appear many times |
| Any type | items need not match |
| Hashable | it can be a dictionary key or go in a set |
That last one is a real advantage a list does not have:
A tuple can be a key; a list cannot
by_position = {("Maths", 1): 78}
print(by_position[("Maths", 1)])
{["Maths", 1]: 78}
Mutable vs Immutable
A tuple refuses every kind of change:
A tuple refuses every change
marks = (78, 85)
marks[0] = 90
And it has no methods that change it
marks = (78, 85)
marks.append(60)
One subtlety worth knowing: a tuple holds references, so a mutable item inside it can still change.
A list inside a tuple can still change
record = ("Asha", [78, 85])
record[1].append(60)
print(record)
The tuple still holds the same two items — the same text and the same list. The list itself changed. The tuple is immutable; its contents are not necessarily.
A tuple freezes which objects it holds, not what those objects contain. A list inside a tuple can still grow and shrink, which is also why such a tuple cannot be a dictionary key.
That is also why a tuple containing a list cannot be a dictionary key:
A tuple is only hashable if its items are
{(78, 85): "fine"}
{("Asha", [78, 85]): "not fine"}
Lists vs Tuples
Since a tuple is so close to a list, here they are side by side:
| List | Tuple | |
|---|---|---|
| Written | [78, 85] | (78, 85) |
| Changeable | yes | no |
| Methods | eleven | two |
| As a dictionary key | no | yes, if its items are |
| Memory | more | less |
| Use for | a collection that grows or changes | a fixed record, a return value |
The size difference
import sys
as_list = [78, 85, 60]
as_tuple = (78, 85, 60)
print("list: ", sys.getsizeof(as_list), "bytes")
print("tuple:", sys.getsizeof(as_tuple), "bytes")
The practical rule: a list is many of one thing; a tuple is one thing made of several parts. A list of marks is a list. One result — name, subject, mark — is a tuple.
The rule in use
results = [
("Asha", "Maths", 78),
("Ravi", "Science", 85),
]
for name, subject, mark in results:
print(f"{name} scored {mark} in {subject}")
A list of tuples: many results, each a fixed record of three parts.
Accessing Tuple Elements
Now that you know how to make a tuple, here is how to reach what is inside one.
Tuple Indexing
Positive Indexing
Counting from the front
result = ("Asha", "Maths", 78)
print(result[0])
print(result[2])
Negative Indexing
Counting from the back
result = ("Asha", "Maths", 78)
print(result[-1])
print(result[-3])
Past the end
result = ("Asha", "Maths")
print(result[5])
Tuple Slicing
Slicing gives back a new tuple.
Slicing a tuple
marks = (78, 85, 60, 92, 45)
print(marks[1:3])
print(marks[:2])
print(marks[-2:])
print(marks[::2])
print(marks[::-1])
Slicing does not break immutability: the original is untouched and a new tuple is made.
Accessing Nested Tuples
A tuple can hold other tuples, and you reach inside with two indexes:
Tuples inside tuples
term = (("Maths", 78), ("Science", 85))
print(term[0])
print(term[0][0])
print(term[1][1])
for subject, mark in term:
print(subject, mark)
Modifying Tuples
A tuple cannot be modified, so this section is about what to do instead — and why the restriction helps.
Tuple Immutability
There is no way to change a tuple. That is the whole point: anything holding a reference to it knows it cannot change underneath them.
Why that is useful
SCHOOL_DAYS = ("Monday", "Tuesday", "Wednesday", "Thursday", "Friday")
def add_day(days):
try:
days.append("Saturday")
return "changed it"
except AttributeError:
return "could not change it"
print(add_day(SCHOOL_DAYS))
print(SCHOOL_DAYS)
Handing a list to that function would have changed it. A tuple cannot be changed by anyone.
Creating Modified Tuples
To "change" a tuple, build a new one.
Building a changed copy
result = ("Asha", "Maths", 78)
updated = result[:2] + (90,)
print(updated)
print(result)
as_list = list(result)
as_list[2] = 90
updated = tuple(as_list)
print(updated)
The second form is the one to use when several items change: convert to a list, change it, convert back.
Concatenating Tuples
Joining tuples
term1 = (78, 85)
term2 = (60, 92)
print(term1 + term2)
print(term1 * 2)
print(term1)
Both build new tuples. += looks like a change but is not:
+= makes a new tuple
marks = (78, 85)
first = marks
marks += (60,)
print("marks:", marks)
print("first:", first)
print("Same object?", marks is first)
marks points at a new tuple. The original still exists, unchanged, and first still holds it.
Deleting Tuples
Deleting an Entire Tuple
del can remove the whole name.
Deleting the name
marks = (78, 85)
print(marks)
del marks
print(marks)
Why Individual Elements Cannot Be Deleted
One item cannot be deleted, for the same reason one cannot be changed:
Deleting one item is refused
marks = (78, 85, 60)
del marks[0]
Deleting an item would change the tuple, and a tuple cannot change. Build a new one instead:
Removing an item by rebuilding
marks = (78, 85, 60)
without_first = marks[1:]
without_85 = tuple(mark for mark in marks if mark != 85)
print(without_first)
print(without_85)
print(marks)
Tuple Operations
The remaining operations work much as they do with lists.
Concatenation and Repetition
+ and *
print((78, 85) + (60,))
print((0,) * 5)
Membership Operators
in and not in
marks = (78, 85, 60)
print(78 in marks)
print(99 in marks)
print(99 not in marks)
Iterating Through Tuples
Looping over a tuple
result = ("Asha", "Maths", 78)
for item in result:
print(item)
for position, item in enumerate(result):
print(position, item)
Looping is safe in a way it never is with a list: nothing can add or remove items partway through.
Tuple Packing and Unpacking
One part of tuples is worth a section of its own, because it explains things you have been using all along.
Tuple Packing
Packing is putting several values into one tuple. It happens whenever you write values separated by commas.
Packing
result = "Asha", "Maths", 78
print(result)
print(type(result).__name__)
This is why a function can appear to return several values:
A function returning 'several' values
def summarise(marks):
return min(marks), max(marks), sum(marks)
answer = summarise([78, 85, 60])
print(answer)
print(type(answer).__name__)
It returned one tuple. Python packed the three values on the way out.
Tuple Unpacking
Unpacking is the reverse: taking a tuple apart into separate names.
Unpacking
result = ("Asha", "Maths", 78)
name, subject, mark = result
print(name)
print(subject)
print(mark)
The counts must match:
Too few names
result = ("Asha", "Maths", 78)
name, subject = result
A * collects whatever is left over:
Collecting the rest
marks = (78, 85, 60, 92)
first, *rest = marks
first, *middle, last = marks
print(first, rest)
print(first, middle, last)
The collected part is always a list, even inside a tuple unpacking.
_ is the conventional name for a value you do not want:
Ignoring part of a record
result = ("Asha", "Maths", 78)
name, _, mark = result
print(name, mark)
Multiple Variable Assignment
Packing and unpacking together explain two things you have been using since lesson 2.
Where multiple assignment comes from
a, b, c = 1, 2, 3
print(a, b, c)
The right-hand side packs into (1, 2, 3); the left-hand side unpacks it.
And why swapping works
first = 78
second = 85
first, second = second, first
print(first, second)
The right side is packed into a tuple before anything is assigned, so no temporary variable is needed and nothing is overwritten halfway.
Unpacking is what makes looping over pairs read well:
Unpacking in a loop
results = [("Asha", 78), ("Ravi", 85)]
for name, mark in results:
print(name, mark)
for position, (name, mark) in enumerate(results, start=1):
print(position, name, mark)
Built-in Functions with Tuples
The same built-ins that work on lists work on tuples, with one surprise:
The built-ins that work on a tuple
marks = (78, 85, 60, 92)
print("len: ", len(marks))
print("max: ", max(marks))
print("min: ", min(marks))
print("sum: ", sum(marks))
print("sorted:", sorted(marks))
print("tuple: ", tuple([78, 85]))
sorted() on a tuple gives back a list, not a tuple:
sorted gives a list
marks = (78, 20, 85)
ordered = sorted(marks)
print(ordered, type(ordered).__name__)
print(tuple(sorted(marks)))
zip builds tuples
subjects = ("Maths", "Science")
marks = (78, 85)
pairs = list(zip(subjects, marks))
print(pairs)
print(type(pairs[0]).__name__)
Every pair zip() produces is a tuple, which is why unpacking in a for loop works so naturally.
Tuple Methods
A tuple cannot change, so it has only two methods — the two that ask a question rather than change anything.
count()
count() says how many times a value appears:
count
marks = (78, 85, 78, 60, 78)
print(marks.count(78))
print(marks.count(99))
index()
index() says where a value first appears:
index
marks = (78, 85, 60, 85)
print(marks.index(85))
print(marks.index(85, 2))
index raises when the value is missing
marks = (78, 85)
print(marks.index(99))
Checking first
marks = (78, 85)
if 99 in marks:
print(marks.index(99))
else:
print("99 is not in the tuple")
Two methods instead of eleven is not a shortcoming. Everything a tuple leaves out is something that would change it, and not being able to change is what a tuple is for.
Common mistakes
Before moving on, here are some of the mistakes beginners make with tuples.
Each row is one mistake. The middle column is what you will actually see on screen.
| Mistake | What you see | Why it happens | Fix |
|---|---|---|---|
(78) meant as a tuple | An int, and len() fails | Brackets alone do not make a tuple | (78,) with a trailing comma |
| Assigning to an item | TypeError: 'tuple' object does not support item assignment | Tuples are immutable | Build a new tuple |
Calling append() | AttributeError: 'tuple' object has no attribute 'append' | A tuple has only count and index | Use a list, or rebuild |
del marks[0] | TypeError: 'tuple' object doesn't support item deletion | Deleting would change it | marks[1:], or rebuild |
Expecting += to change it | The old tuple is untouched | += makes a new tuple and rebinds the name | Expect a new object |
| Expecting a nested list to be frozen | The inner list still changes | A tuple freezes its references, not its contents | Keep tuples inside tuples |
| A tuple with a list as a dict key | TypeError: unhashable type: 'list' | All items must be hashable | Use tuples all the way down |
| Unpacking with the wrong number of names | ValueError: not enough values to unpack | The counts must match | Count both sides, or use *rest |
Expecting sorted() to give a tuple | A list comes back | sorted() always returns a list | tuple(sorted(marks)) |
| Using a tuple for a growing collection | Rebuilding on every change | A tuple is for a fixed record | Use a list |
What to Remember
- A tuple is ordered like a list but cannot be changed after it is made.
- The comma makes a tuple, not the brackets. A tuple of one needs a trailing comma:
(78,). - A tuple can be a dictionary key or go in a set; a list cannot.
- A tuple freezes which objects it holds, not their contents — a list inside one can still change.
- There is no way to change a tuple: slice and join, or convert to a list and back.
+=on a tuple builds a new tuple and moves the name to it.- A tuple has only two methods,
count()andindex(), because everything else would change it. - Packing happens whenever values are separated by commas; unpacking takes them apart.
- A function that "returns several values" returns one packed tuple.
a, b = b, aworks because the right side is packed before anything is assigned.- A list is many of one thing; a tuple is one thing made of several parts.
Next: Sets