Previous | Tutorial index | Next

Tutorial 4: Lists and Tuples – Understanding the Differences

Learning Objectives

Overview

Lists and tuples are two of the most fundamental sequence types in Python. They both store ordered collections of items, support indexing and slicing, and can contain any Python objects—numbers, strings, even other sequences. However, their single most important difference—mutability—shapes how, when, and why you use each. This tutorial dives deep into both types, covers their methods and built‑in functions, and provides clear guidelines on choosing the right tool for the job.

1. Lists – The Mutable Workhorse

1.1 Definition and Creation

A list is an ordered, mutable collection of items. You create a list using square brackets [], with items separated by commas.

empty_list = [] numbers = [1, 2, 3, 4] mixed = [10, "hello", 3.14, [5, 6]] # lists can hold any types

You can also create a list using the list() constructor from any iterable:

letters = list("abc") # ['a', 'b', 'c'] ranged = list(range(5)) # [0, 1, 2, 3, 4]

1.2 Indexing and Slicing

As sequences, lists support the same indexing and slicing operations as strings:

nums = [10, 20, 30, 40, 50] print(nums[1]) # 20 print(nums[-1]) # 50 print(nums[1:4]) # [20, 30, 40] print(nums[::2]) # [10, 30, 50] print(nums[::-1]) # [50, 40, 30, 20, 10] (reverse)

1.3 Mutability – The Key Feature

Unlike strings and tuples, lists are mutable – you can change, add, or remove elements after creation.

nums[0] = 99 print(nums) # [99, 20, 30, 40, 50]
nums.append(60) # [99, 20, 30, 40, 50, 60] nums.extend([70, 80]) # [99, 20, 30, 40, 50, 60, 70, 80] nums.insert(2, 25) # [99, 20, 25, 30, 40, 50, 60, 70, 80]
last = nums.pop() # 80, nums becomes [99, 20, 25, 30, 40, 50, 60, 70] second = nums.pop(1) # 20, nums becomes [99, 25, 30, 40, 50, 60, 70] nums.remove(25) # [99, 30, 40, 50, 60, 70] nums.clear() # []

1.4 Other Useful List Methods

letters = ['b', 'a', 'd', 'c'] letters.sort() # ['a', 'b', 'c', 'd'] letters.reverse() # ['d', 'c', 'b', 'a']

Important: sort() and reverse() modify the list and return None. They are in‑place methods.

1.5 List Concatenation and Repetition

Like all sequences, lists support + and *:

a = [1, 2] b = [3, 4] print(a + b) # [1, 2, 3, 4] print(a * 3) # [1, 2, 1, 2, 1, 2]

2. Tuples – The Immutable Counterpart

2.1 Definition and Creation

A tuple is an ordered, immutable collection of items. You create a tuple using parentheses (), with items separated by commas.

empty_tuple = () single = (42,) # note the trailing comma – without it, it's just the integer 42 numbers = (1, 2, 3) mixed = (10, "hello", 3.14)

You can also use the tuple() constructor from any iterable:

t = tuple([1, 2, 3]) # (1, 2, 3)

2.2 Indexing and Slicing

Tuples support the same indexing and slicing as lists (and they return new tuples).

t = (10, 20, 30, 40) print(t[1]) # 20 print(t[-1]) # 40 print(t[1:3]) # (20, 30)

2.3 Immutability – The Decisive Difference

Once a tuple is created, you cannot change, add, or remove elements. Any attempt results in a TypeError.

t = (1, 2, 3) # t[0] = 99 # TypeError: 'tuple' object does not support item assignment # t.append(4) # AttributeError: 'tuple' object has no attribute 'append'

However, if a tuple contains a mutable object (like a list), that object itself can be modified – but the tuple still holds the same reference.

t = (1, [2, 3], 4) t[1].append(99) # allowed – the list is mutated print(t) # (1, [2, 3, 99], 4)

2.4 Tuple Methods

Tuples have only two methods (because they are immutable):

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

2.5 Tuple Concatenation and Repetition

Like lists, tuples support + and *:

a = (1, 2) b = (3, 4) print(a + b) # (1, 2, 3, 4) print(a * 3) # (1, 2, 1, 2, 1, 2)

3. Key Differences at a Glance

Feature List Tuple
Mutability Mutable Immutable
Syntax [1, 2, 3] (1, 2, 3)
Methods Many (append, extend, insert, remove, pop, sort, reverse, clear, copy, index, count) Few (count, index)
Performance Slightly slower, more memory Slightly faster, less memory
Hashable? No (cannot be used as dict keys) Yes (if all elements are hashable)
Use Cases Dynamic collections, homogenous data Fixed collections, heterogenous data (like a record)
Iteration Fast Slightly faster

Memory and Performance: Tuples are more memory‑efficient because they don't need overallocation for resizing. They are also slightly faster to access.

4. Common Operations – Both Lists and Tuples

Many built‑in functions work on both:

nums = [3, 1, 4, 2] print(len(nums)) # 4 print(min(nums)) # 1 print(max(nums)) # 4 print(sum(nums)) # 10 print(sorted(nums)) # [1, 2, 3, 4] (new list) print(sorted(nums, reverse=True)) # [4, 3, 2, 1]

5. Advanced Topics

5.1 Tuple Unpacking

One of the most elegant features of tuples is unpacking – assigning each element to a variable.

point = (3, 5) x, y = point # x=3, y=5 print(x, y)

You can use * to capture remaining elements (Python 3+):

first, *rest = (1, 2, 3, 4) # first=1, rest=[2,3,4]

5.2 List Comprehensions

A concise way to create lists from iterables:

squares = [x**2 for x in range(5)] # [0, 1, 4, 9, 16] even = [x for x in range(10) if x % 2 == 0] # [0, 2, 4, 6, 8]

5.3 Converting Between Lists and Tuples

t = (1, 2, 3) lst = list(t) # [1, 2, 3] t2 = tuple(lst) # (1, 2, 3)

5.4 Nested Sequences

Both can contain other sequences:

matrix = [[1, 2], [3, 4]] # list of lists coordinates = ((0,0), (1,1), (2,2)) # tuple of tuples

Access nested elements with repeated indexing:

print(matrix[0][1]) # 2

6. When to Use Which? – Practical Guidelines

📝 Quiz – Check Your Understanding

  1. Which of the following correctly creates a tuple with a single element 42?

    Answer(C) `(42,)`
  2. What is the output of the following code?

    lst = [1, 2, 3] lst.append([4, 5]) print(len(lst))
    Answer(C) 4 – because `append` adds the entire list as one element
  3. True or False: Tuples are immutable, meaning you cannot change any element, even if the element itself is a mutable object.

    AnswerFalse – the tuple itself is immutable, but if it contains a mutable object, that object can be changed.
  4. Which method adds an element at the end of a list?

    Answer(C) `append()`
  5. What does [1, 2, 3].pop(1) return?

    Answer(B) 2 – because `pop(1)` removes and returns the element at index 1
  6. Which of the following can be used as a dictionary key?

    Answer(B) `(1, 2)` – tuples are hashable; lists and sets are not.
  7. What is the result of list("hello")?

    Answer(A) `['h', 'e', 'l', 'l', 'o']`
  8. Given t = (5, 2, 5, 1), what does t.count(5) return?

    Answer(B) 2
  9. Which method sorts a list in place?

    Answer(B) `sort()`
  10. What is the output of [1, 2] * 3?

    Answer(A) `[1, 2, 1, 2, 1, 2]`

💻 Exercises – Practice Makes Perfect

Exercise 1: List Operations
Start with numbers = [5, 3, 8, 1, 9, 2]. Perform the following operations in order:

  1. Append 7 to the end.
  2. Insert 4 at index 2.
  3. Remove the element 1.
  4. Sort the list in ascending order.
  5. Reverse the list.
  6. Pop the last element and store it in a variable.
  7. Print the final list and the popped value.
Sample Solution ```python numbers = [5, 3, 8, 1, 9, 2] numbers.append(7) numbers.insert(2, 4) numbers.remove(1) numbers.sort() numbers.reverse() popped = numbers.pop() print("Final list:", numbers) print("Popped value:", popped) # Final list: [9, 8, 5, 4, 3], popped: 2 ```

Exercise 2: Tuple Packing and Unpacking
Write a function get_user_info() that returns a tuple (name, age, city). Then, call it and unpack the values. Create a second tuple (name, age) by slicing the first tuple. Print both.

Sample Solution ```python def get_user_info(): return ("Alice", 30, "NYC") name, age, city = get_user_info() print(name, age, city) short = (name, age) print(short) ```

Exercise 3: Count Occurrences
Given data = [1, 2, 3, 2, 4, 2, 5], write a program that:

Sample Solution ```python data = [1, 2, 3, 2, 4, 2, 5] print(data.count(2)) print(data.index(4)) try: data.index(3) print("3 is in the list") except ValueError: print("3 is not in the list") ```

Exercise 4: List of Tuples
Create a list of tuples representing students: [("Alice", 85), ("Bob", 92), ("Charlie", 78)].

Sample Solution ```python students = [("Alice", 85), ("Bob", 92), ("Charlie", 78)] for name, score in students: print(f"{name}: {score}") highest = max(students, key=lambda x: x[1]) print("Highest:", highest) students.sort(key=lambda x: x[1], reverse=True) print("Sorted:", students) ```

Exercise 5: Matrix Transposition
Given a 2D list (matrix) matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]], write code to produce its transpose:

[[1, 4, 7], [2, 5, 8], [3, 6, 9]]

Use list comprehensions and/or loops.

Sample Solution ```python matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]] transpose = [[matrix[j][i] for j in range(len(matrix))] for i in range(len(matrix[0]))] print(transpose) ```

🏠 Homework – Deeper Thinking

Short Answer Questions

1. Inventory System
Design a simple inventory system using a list of tuples. Each tuple represents an item: (item_id, name, quantity, price). Start with:

inventory = [ (1, "Laptop", 5, 999.99), (2, "Mouse", 20, 19.99), (3, "Keyboard", 10, 49.99) ]

Write functions to:

Sample Answer ```python def add_item(inventory, id, name, qty, price): inventory.append((id, name, qty, price))

def update_quantity(inventory, id, new_qty): for i, item in enumerate(inventory): if item[0] == id: inventory[i] = (item[0], item[1], new_qty, item[3]) return raise ValueError("Item not found")

def remove_item(inventory, id): for i, item in enumerate(inventory): if item[0] == id: del inventory[i] return raise ValueError("Item not found")

def total_value(inventory): return sum(item[2] * item[3] for item in inventory)

def display_inventory(inventory): print(f"{'ID':>3} {'Name':<10} {'Qty':>4} {'Price':>8} {'Total':>8}") for item in inventory: total = item[2] * item[3] print(f"{item[0]:>3} {item[1]:<10} {item[2]:>4} {item[3]:>8.2f} {total:>8.2f}")

</details> **2. Unique Elements** Write a function `unique_preserve_order(lst)` that returns a new list with duplicate elements removed, preserving the original order of first occurrence. Use only list methods (no sets allowed). Test with `[1, 2, 2, 3, 1, 4]` → `[1, 2, 3, 4]`. <details><summary>Sample Answer</summary> ```python def unique_preserve_order(lst): result = [] for item in lst: if item not in result: result.append(item) return result

3. Rotate a List
Write a function rotate(lst, k) that rotates the list to the right by k positions (modulo length). Example: rotate([1,2,3,4,5], 2)[4,5,1,2,3]. Use slicing and concatenation. Do not use loops. Also, handle negative k (rotate left) and k=0.

Sample Answer ```python def rotate(lst, k): if not lst: return lst k = k % len(lst) return lst[-k:] + lst[:-k] ```

4. Tuple as a Record – Student Grades
Write a program that reads student data from a multi‑line string (simulating a CSV file) where each line is "Name,Math,Science,English". Use split() to parse each line into a tuple (name, math, science, english) (convert scores to ints). Store all tuples in a list. Then:

Sample Answer ```python data = """Alice,85,90,78 Bob,70,80,75 Charlie,92,88,95""" lines = data.strip().split('\n') students = [] for line in lines: name, math, sci, eng = line.split(',') students.append((name, int(math), int(sci), int(eng)))

for name, math, sci, eng in students: avg = (math + sci + eng) / 3 print(f"{name}: {avg:.2f}")

highest = max(students, key=lambda s: (s[1]+s[2]+s[3])/3) print("Highest avg:", highest[0])

math_avg = sum(s[1] for s in students) / len(students) sci_avg = sum(s[2] for s in students) / len(students) eng_avg = sum(s[3] for s in students) / len(students) print(f"Math avg: {math_avg:.2f}, Science: {sci_avg:.2f}, English: {eng_avg:.2f}")

sorted_by_avg = sorted([(s[0], (s[1]+s[2]+s[3])/3) for s in students], key=lambda x: x[1], reverse=True) print(sorted_by_avg)

</details> #### Essay Questions **5. Deep vs Shallow Copy** This question tests understanding of mutability and copying. Given: ```python original = [1, [2, 3], 4]
Sample Answer ```python import copy original = [1, [2, 3], 4] copy1 = original[:] copy2 = list(original) copy3 = original.copy()

Modify nested list

original[1][0] = 99 print(copy1, copy2, copy3) # all show [1, [99, 3], 4] because the nested list is shared

Modify top-level element

original[0] = 100 print(copy1, copy2, copy3) # copies remain unchanged at index 0

Deep copy

deep = copy.deepcopy(original) original[1][0] = 42 print(deep) # [1, [99, 3], 4] – unaffected because deep copy is independent

Shallow copy copies the top-level container but shares nested objects. Deep copy recursively copies everything. </details> ### Homework Hints - **Q1**: For `update_quantity`, you need to find the index, then create a new tuple: `new_item = (id, name, new_qty, price)` and assign to `inventory[index]`. - **Q2**: Use a new list and check `if item not in new_list`. - **Q3**: `k = k % len(lst)`; then `lst[-k:] + lst[:-k]` for right rotation; for left, `lst[k:] + lst[:k]`. - **Q4**: Parse lines, convert scores to int, use tuple of 4 elements. - **Q5**: Slicing creates a shallow copy; modifying nested list affects all shallow copies. Only `deepcopy` creates independent copies. ## Summary In this tutorial, you have learned: - The syntax and core properties of lists (mutable) and tuples (immutable). - The rich set of list methods and the limited but useful tuple methods. - Common sequence operations and built‑in functions. - Advanced concepts like tuple unpacking and list comprehensions. - Practical guidelines on when to use each type. With this knowledge, you are now equipped to choose the appropriate sequence type for your data, write more efficient and readable code, and avoid common pitfalls related to mutability. **Next Steps**: In Tutorial 5, we will explore **Dictionaries and Sets** – powerful data structures for key‑value mappings and unique collections. *Happy coding with lists and tuples!* <!-- tutorial-navigation:start --> [Previous](t-3.html) | [Tutorial index]() | | [Next](t-5.html) <!-- tutorial-navigation:end -->