Chapter 13 Intermediate 22 min min read Updated 2026-04-06

Tuples in Python

Practice Questions →

In This Chapter

What Is It?

What Are Tuples in Python?

A tuple is an ordered, immutable sequence of items. Tuples look similar to lists but are defined using parentheses () instead of square brackets []. Once a tuple is created, you cannot add, remove, or change its elements.

Tuples can hold items of any data type — integers, strings, floats, booleans, and even other tuples or lists.

Creating Tuples

empty = ()                           # Empty tuple
single = (5,)                        # Single-element tuple (comma required!)
coords = (10, 20)                    # Tuple of two integers
student = ("Aarav", 16, "Class 11")  # Mixed types
nested = ((1, 2), (3, 4))            # Nested tuples
from_list = tuple([1, 2, 3])         # Convert list to tuple

The parentheses are actually optional in most cases. It is the comma that makes a tuple, not the parentheses. However, using parentheses is recommended for clarity.

The Single-Element Tuple Gotcha

This is one of the most common surprises for beginners. Writing (5) does NOT create a tuple — it is just the integer 5 in parentheses (like in a math expression). To create a single-element tuple, you must include a trailing comma: (5,).

not_a_tuple = (5)     # This is just the integer 5
is_a_tuple = (5,)     # This is a tuple containing 5
print(type(not_a_tuple))  # <class 'int'>
print(type(is_a_tuple))   # <class 'tuple'>

Why Does It Matter?

Why Are Tuples Important?

At first glance, tuples may seem like restricted lists. If lists can do everything tuples can do (and more), why do tuples exist? There are several important reasons:

1. Immutability Provides Safety

When you pass a tuple to a function, you are guaranteed it will not be modified. This makes tuples ideal for data that should remain constant: coordinates, RGB colors, database records, configuration settings. Immutability prevents accidental changes and makes your code more predictable.

2. Tuples Can Be Dictionary Keys

Since tuples are immutable (and therefore hashable), they can be used as dictionary keys. Lists cannot be used as keys because they are mutable. This is crucial when you need to use a pair of values (like coordinates) as a lookup key.

locations = {(28.6, 77.2): "Delhi", (19.0, 72.8): "Mumbai"}

3. Tuples Are Faster Than Lists

Because of their immutability, Python can optimize tuples internally. Creating and accessing tuple elements is slightly faster than the equivalent list operations. For large-scale data processing, this performance difference matters.

4. Tuple Packing and Unpacking

Tuples enable elegant patterns like swapping variables (a, b = b, a), returning multiple values from functions, and destructuring sequences. These patterns are used constantly in Python code.

5. Convention and Intent

Using a tuple signals to other programmers that this collection is not meant to be modified. It communicates intent: a tuple of (name, age, grade) represents a fixed record, while a list of students represents a collection that might grow or shrink.

Detailed Explanation

Detailed Explanation

1. Accessing Tuple Elements

Tuples support the same indexing and slicing as lists and strings:

colors = ("red", "green", "blue", "yellow")
colors[0]      # "red"
colors[-1]     # "yellow"
colors[1:3]    # ("green", "blue")
colors[::-1]   # ("yellow", "blue", "green", "red")

Indexing returns a single element. Slicing returns a new tuple.

2. Tuple Immutability

You cannot modify a tuple after creation. Attempting to assign to an index raises a TypeError:

t = (1, 2, 3)
t[0] = 10  # TypeError: 'tuple' object does not support item assignment

You also cannot use append(), remove(), insert(), or any other modifying method. Tuples only have two methods: count() and index().

Important caveat: If a tuple contains a mutable object (like a list), the mutable object inside can still be changed:

t = (1, [2, 3], 4)
t[1].append(5)    # This works! t is now (1, [2, 3, 5], 4)
t[1] = [99]       # This fails! Cannot reassign the tuple element

3. Tuple Methods

Tuples have only two methods:

count(value) returns the number of times a value appears in the tuple.

index(value) returns the index of the first occurrence of a value. Raises ValueError if not found.

t = (1, 2, 3, 2, 4, 2)
t.count(2)    # 3
t.index(3)    # 2

4. Tuple Packing and Unpacking

Packing is creating a tuple from multiple values:

coords = 10, 20, 30    # Packed into a tuple (10, 20, 30)

Unpacking is extracting tuple values into individual variables:

x, y, z = coords       # x=10, y=20, z=30

The number of variables must match the number of elements, unless you use * for extended unpacking.

5. Swapping with Tuples

Python's tuple packing and unpacking enables elegant variable swapping without a temporary variable:

a = 10
b = 20
a, b = b, a    # Now a=20, b=10

The right side creates a tuple (b, a) = (20, 10), then unpacks it into a and b. This is one of Python's most iconic features.

6. Tuples as Dictionary Keys

Because tuples are immutable and hashable, they can serve as dictionary keys. This is useful for mapping coordinate pairs, compound keys, or any combination of values to a result:

grid = {}
grid[(0, 0)] = "origin"
grid[(1, 0)] = "right"
print(grid[(0, 0)])    # "origin"

Lists cannot be used as dictionary keys because they are mutable and not hashable.

7. When to Use Tuples vs Lists

Use tuples when: the data should not change (coordinates, dates, records), you need a hashable type (dictionary keys, set elements), or you want to signal immutability to other developers.

Use lists when: the collection will change (adding/removing items), you need methods like sort(), append(), or extend(), or the data represents a homogeneous collection of similar items.

8. Named Tuples

collections.namedtuple creates tuple subclasses with named fields, making code more readable:

from collections import namedtuple
Student = namedtuple('Student', ['name', 'age', 'grade'])
s = Student('Priya', 16, 'A')
print(s.name)    # 'Priya'
print(s.age)     # 16
print(s[0])      # 'Priya' (indexing still works)

Named tuples combine the immutability of tuples with the readability of named fields.

9. Converting Between Tuples and Lists

tuple(list_obj) converts a list to a tuple. list(tuple_obj) converts a tuple to a list. This is useful when you need to modify data from a tuple: convert to a list, make changes, then convert back.

t = (1, 2, 3)
lst = list(t)      # [1, 2, 3]
lst.append(4)
t = tuple(lst)     # (1, 2, 3, 4)

10. Tuple Concatenation and Nesting

You can concatenate tuples with + and repeat with *:

(1, 2) + (3, 4)    # (1, 2, 3, 4)
(0,) * 5            # (0, 0, 0, 0, 0)

Nested tuples contain tuples as elements:

matrix = ((1, 2), (3, 4), (5, 6))
matrix[1][0]    # 3

Code Examples

Creating Tuples and the Single-Element Gotcha
# Different ways to create tuples
empty = ()
print("Empty tuple:", empty, "Length:", len(empty))

pair = (10, 20)
print("Pair:", pair)

# Single-element tuple REQUIRES a trailing comma
single = (5,)
not_tuple = (5)
print("Single tuple:", single, "Type:", type(single))
print("Not a tuple:", not_tuple, "Type:", type(not_tuple))

# Parentheses are optional
no_parens = 1, 2, 3
print("Without parens:", no_parens, "Type:", type(no_parens))

# Convert list to tuple
from_list = tuple(["a", "b", "c"])
print("From list:", from_list)
Tuples can be created with or without parentheses. The trailing comma is what makes a single-element tuple: (5,) is a tuple, (5) is just an integer. The tuple() constructor converts any iterable to a tuple.
Empty tuple: () Length: 0 Pair: (10, 20) Single tuple: (5,) Type: <class 'tuple'> Not a tuple: 5 Type: <class 'int'> Without parens: (1, 2, 3) Type: <class 'tuple'> From list: ('a', 'b', 'c')
Tuple Indexing and Slicing
student = ("Rohan", 17, "Class 12", 92.5)

# Indexing
print("Name:", student[0])
print("Last element:", student[-1])

# Slicing
print("Middle elements:", student[1:3])
print("Reversed:", student[::-1])

# Iterating
print("\nAll elements:")
for item in student:
    print(f"  {item} (type: {type(item).__name__})")

# Length and membership
print("\nLength:", len(student))
print("Has 'Rohan':", "Rohan" in student)
print("Has 'Priya':", "Priya" in student)
Tuples support all the same read operations as lists: indexing, negative indexing, slicing, iteration, len(), and the in operator. Slicing a tuple returns a new tuple.
Name: Rohan Last element: 92.5 Middle elements: (17, 'Class 12') Reversed: (92.5, 'Class 12', 17, 'Rohan') All elements: Rohan (type: str) 17 (type: int) Class 12 (type: str) 92.5 (type: float) Length: 4 Has 'Rohan': True Has 'Priya': False
Tuple Immutability
t = (10, 20, 30)

# Attempting to modify raises TypeError
try:
    t[0] = 99
except TypeError as e:
    print("Error:", e)

# But a mutable object INSIDE a tuple can be changed
t2 = (1, [2, 3], 4)
print("Before:", t2)
t2[1].append(5)
print("After modifying inner list:", t2)

# Cannot reassign the element though
try:
    t2[1] = [99]
except TypeError as e:
    print("Error:", e)
Tuples are immutable: you cannot change, add, or remove elements. However, if a tuple contains a mutable object (like a list), that inner object can still be modified. The tuple's immutability only prevents reassigning the reference at that index, not modifying the object the reference points to.
Error: 'tuple' object does not support item assignment Before: (1, [2, 3], 4) After modifying inner list: (1, [2, 3, 5], 4) Error: 'tuple' object does not support item assignment
Tuple Packing and Unpacking
# Packing
coords = 10, 20, 30
print("Packed:", coords)

# Unpacking
x, y, z = coords
print(f"x={x}, y={y}, z={z}")

# Swapping variables
a = 5
b = 10
print(f"Before swap: a={a}, b={b}")
a, b = b, a
print(f"After swap: a={a}, b={b}")

# Extended unpacking with *
first, *middle, last = (1, 2, 3, 4, 5)
print(f"first={first}, middle={middle}, last={last}")

# Unpacking in a loop
students = [("Aarav", 90), ("Priya", 95), ("Meera", 88)]
for name, marks in students:
    print(f"{name}: {marks}")
Packing creates a tuple from values. Unpacking extracts values into variables. Swapping a, b = b, a works by packing the right side into a tuple (b, a) and unpacking it into a and b. Extended unpacking with * collects remaining items. Unpacking in loops is common for iterating over lists of tuples.
Packed: (10, 20, 30) x=10, y=20, z=30 Before swap: a=5, b=10 After swap: a=10, b=5 first=1, middle=[2, 3, 4], last=5 Aarav: 90 Priya: 95 Meera: 88
Tuples as Dictionary Keys
# Using tuples as dictionary keys (coordinates example)
locations = {}
locations[(0, 0)] = "Origin"
locations[(1, 0)] = "East"
locations[(0, 1)] = "North"
locations[(-1, 0)] = "West"

print(locations[(0, 0)])
print(locations[(1, 0)])

# Why lists cannot be keys
try:
    bad = {[1, 2]: "value"}
except TypeError as e:
    print("Error:", e)

# Practical example: counting coordinate visits
moves = [(0,0), (1,0), (0,1), (1,0), (0,0)]
visit_count = {}
for pos in moves:
    visit_count[pos] = visit_count.get(pos, 0) + 1
print("Visit counts:", visit_count)
Tuples can be dictionary keys because they are immutable and hashable. Lists cannot be keys because they are mutable (a list could change after being used as a key, breaking the dictionary). This is one of the most practical reasons to choose tuples over lists.
Origin East Error: unhashable type: 'list' Visit counts: {(0, 0): 2, (1, 0): 2, (0, 1): 1}
Named Tuples
from collections import namedtuple

# Define a named tuple type
Student = namedtuple('Student', ['name', 'age', 'grade'])

# Create instances
s1 = Student('Aarav', 16, 'A')
s2 = Student('Priya', 15, 'A+')

# Access by name (readable)
print(f"{s1.name} is {s1.age} years old, grade: {s1.grade}")

# Access by index (still works)
print(f"First field: {s2[0]}")

# Immutable like regular tuples
try:
    s1.age = 17
except AttributeError as e:
    print("Error:", e)

# Convert to dictionary
print("As dict:", s1._asdict())
Named tuples from collections.namedtuple create tuple subclasses with named fields. You can access elements by name (s.name) or by index (s[0]). They are immutable like regular tuples. The _asdict() method converts to a dictionary. Named tuples make code more self-documenting.
Aarav is 16 years old, grade: A First field: Priya Error: can't set attribute As dict: {'name': 'Aarav', 'age': 16, 'grade': 'A'}
Tuple Concatenation and Conversion
# Concatenation
t1 = (1, 2, 3)
t2 = (4, 5, 6)
t3 = t1 + t2
print("Concatenated:", t3)

# Repetition
zeros = (0,) * 5
print("Repeated:", zeros)

# Convert between list and tuple
original = (10, 20, 30)
temp_list = list(original)  # Convert to list
temp_list.append(40)        # Modify the list
updated = tuple(temp_list)  # Convert back to tuple
print("Original:", original)
print("Updated:", updated)

# Tuple from string
chars = tuple("Python")
print("From string:", chars)
Tuples support + for concatenation and * for repetition. To modify a tuple, convert to list, make changes, then convert back. The tuple() constructor converts any iterable. tuple("Python") creates a tuple of individual characters.
Concatenated: (1, 2, 3, 4, 5, 6) Repeated: (0, 0, 0, 0, 0) Original: (10, 20, 30) Updated: (10, 20, 30, 40) From string: ('P', 'y', 't', 'h', 'o', 'n')

Common Mistakes

Forgetting the Comma in a Single-Element Tuple

t = (5)
print(type(t))  # <class 'int'> - NOT a tuple!
No error, but t is an integer, not a tuple.
t = (5,)
print(type(t))  # <class 'tuple'>
(5) is just the integer 5 in parentheses, like a math expression. To create a single-element tuple, you MUST include a trailing comma: (5,). This is one of the most common tuple mistakes in Python.

Trying to Modify a Tuple Element

coords = (10, 20, 30)
coords[0] = 15  # TypeError!
TypeError: 'tuple' object does not support item assignment
coords = (10, 20, 30)
coords = (15,) + coords[1:]  # Create a new tuple
print(coords)  # (15, 20, 30)
Tuples are immutable. You cannot change individual elements. To create a modified version, build a new tuple using concatenation and slicing, or convert to a list, modify, and convert back.

Unpacking with Wrong Number of Variables

t = (1, 2, 3)
a, b = t  # ValueError!
ValueError: too many values to unpack (expected 2)
t = (1, 2, 3)
a, b, c = t  # Match the number of elements
# Or use * to collect extras
a, *rest = t  # a=1, rest=[2, 3]
When unpacking, the number of variables must match the number of elements in the tuple. Use * to collect remaining elements into a list if you do not know the exact count.

Assuming Tuple Immutability Protects Inner Mutable Objects

t = ([1, 2], [3, 4])
# Many assume this is fully immutable
t[0].append(99)
print(t)  # ([1, 2, 99], [3, 4]) - inner list was modified!
No error, but the inner list was changed even though it is inside a tuple.
# Be aware that mutable objects inside tuples CAN be changed
t = ([1, 2], [3, 4])
# The tuple prevents reassigning t[0] to a new object
# But it does NOT prevent modifying the list object at t[0]
# For truly immutable data, use tuples of immutable objects
Tuple immutability means you cannot reassign the references stored in the tuple (e.g., t[0] = new_list fails). But if a reference points to a mutable object (like a list), that object can still be modified through its own methods. For truly immutable data, ensure all elements are themselves immutable.

Summary

  • Tuples are ordered, immutable sequences created with parentheses () or just commas. Once created, their elements cannot be changed, added, or removed.
  • A single-element tuple requires a trailing comma: (5,) is a tuple, (5) is just an integer. This is a very common gotcha.
  • Tuples support indexing, negative indexing, slicing, iteration, len(), and the 'in' operator — same read operations as lists.
  • Tuples have only two methods: count() and index(). They lack all modifying methods (append, remove, sort, etc.) because they are immutable.
  • Tuple packing (a, b = 10, 20) and unpacking (x, y = tuple_var) are powerful patterns. Variable swapping (a, b = b, a) uses this internally.
  • Tuples can be used as dictionary keys and set elements because they are hashable. Lists cannot because they are mutable.
  • A tuple containing a mutable object (like a list) is not fully immutable. The inner mutable object can still be modified.
  • Use tuples for fixed collections (coordinates, records, function return values). Use lists for collections that need to grow or change.
  • Named tuples (collections.namedtuple) add named field access to tuples, making code more readable while keeping immutability.
  • Convert between tuples and lists with tuple() and list(). To modify a tuple, convert to list, make changes, then convert back.

Ready to Practice?

Test your understanding with 50+ practice questions on this topic.

Go to Practice Questions

Want to learn Python with a live mentor?

Explore our Python course