Lists and Tuples in Python
Lists and tuples are fundamental data structures in Python for storing collections of items. They allow you to group related data together and perform operations on multiple values at once. Understanding these structures is essential for effective Python programming.
What are Lists?
A list is an ordered, mutable (changeable) collection that can hold items of different types.
# Creating lists
fruits = ['apple', 'banana', 'cherry']
numbers = [1, 2, 3, 4, 5]
mixed = [1, 'hello', 3.14, True]
empty_list = []
print(fruits)
print(f"Length: {len(fruits)}")
Key Characteristics of Lists
- Ordered: Items maintain their position
- Mutable: Can be modified after creation
- Allow duplicates: Can contain the same value multiple times
- Indexed: Access items by position (starting at 0)
- Dynamic: Can grow or shrink in size
Creating Lists
# Various ways to create lists
# Direct assignment
colors = ['red', 'green', 'blue']
# Using list() constructor
numbers = list(range(5)) # [0, 1, 2, 3, 4]
letters = list('hello') # ['h', 'e', 'l', 'l', 'o']
# Empty list
empty1 = []
empty2 = list()
# List with repeated values
zeros = [0] * 5 # [0, 0, 0, 0, 0]
# List comprehension
squares = [x**2 for x in range(5)] # [0, 1, 4, 9, 16]
print(f"Colors: {colors}")
print(f"Numbers: {numbers}")
print(f"Squares: {squares}")
Accessing List Elements
Indexing
fruits = ['apple', 'banana', 'cherry', 'date', 'elderberry']
# Access by index (0-based)
print(fruits[0]) # 'apple' (first item)
print(fruits[2]) # 'cherry' (third item)
# Negative indexing (from end)
print(fruits[-1]) # 'elderberry' (last item)
print(fruits[-2]) # 'date' (second from last)
# Get first and last
first = fruits[0]
last = fruits[-1]
print(f"First: {first}, Last: {last}")
Slicing
numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
# Basic slicing: list[start:end]
print(numbers[2:5]) # [2, 3, 4] (items 2, 3, 4)
print(numbers[:3]) # [0, 1, 2] (first 3)
print(numbers[7:]) # [7, 8, 9] (from 7 to end)
print(numbers[:]) # [0, 1, ... 9] (entire list copy)
# Slicing with step: list[start:end:step]
print(numbers[::2]) # [0, 2, 4, 6, 8] (every 2nd item)
print(numbers[1::2]) # [1, 3, 5, 7, 9] (odd indices)
print(numbers[::-1]) # [9, 8, 7, ... 0] (reversed)
# Negative indices in slicing
print(numbers[-3:]) # [7, 8, 9] (last 3)
print(numbers[:-2]) # [0, 1, ... 7] (all but last 2)
Modifying Lists
Changing Items
fruits = ['apple', 'banana', 'cherry']
# Change single item
fruits[1] = 'blueberry'
print(fruits) # ['apple', 'blueberry', 'cherry']
# Change multiple items with slicing
numbers = [0, 1, 2, 3, 4, 5]
numbers[1:4] = [10, 20, 30]
print(numbers) # [0, 10, 20, 30, 4, 5]
Adding Items
# append(): Add single item to end
fruits = ['apple', 'banana']
fruits.append('cherry')
print(fruits) # ['apple', 'banana', 'cherry']
# insert(): Add item at specific position
fruits.insert(1, 'blueberry')
print(fruits) # ['apple', 'blueberry', 'banana', 'cherry']
# extend(): Add multiple items
fruits.extend(['date', 'elderberry'])
print(fruits) # ['apple', 'blueberry', 'banana', 'cherry', 'date', 'elderberry']
# Using + operator
more_fruits = fruits + ['fig', 'grape']
print(more_fruits)
# Using += operator
fruits += ['honeydew']
print(fruits)
Removing Items
fruits = ['apple', 'banana', 'cherry', 'date', 'banana']
# remove(): Remove first occurrence of value
fruits.remove('banana')
print(fruits) # ['apple', 'cherry', 'date', 'banana']
# pop(): Remove and return item at index (default: last)
last_fruit = fruits.pop()
print(f"Removed: {last_fruit}")
print(fruits)
second_fruit = fruits.pop(1)
print(f"Removed: {second_fruit}")
print(fruits)
# del: Delete by index or slice
numbers = [0, 1, 2, 3, 4, 5]
del numbers[2] # Remove item at index 2
print(numbers)
del numbers[1:3] # Remove slice
print(numbers)
# clear(): Remove all items
fruits.clear()
print(fruits) # []
List Methods
# Sort
numbers = [3, 1, 4, 1, 5, 9, 2, 6]
numbers.sort() # Sort in place
print(numbers) # [1, 1, 2, 3, 4, 5, 6, 9]
numbers.sort(reverse=True) # Sort descending
print(numbers) # [9, 6, 5, 4, 3, 2, 1, 1]
# sorted(): Return new sorted list (doesn't modify original)
original = [3, 1, 4, 1, 5]
sorted_list = sorted(original)
print(f"Original: {original}")
print(f"Sorted: {sorted_list}")
# reverse(): Reverse in place
numbers = [1, 2, 3, 4, 5]
numbers.reverse()
print(numbers) # [5, 4, 3, 2, 1]
# count(): Count occurrences
fruits = ['apple', 'banana', 'apple', 'cherry', 'apple']
apple_count = fruits.count('apple')
print(f"Apples: {apple_count}") # 3
# index(): Find first index of value
position = fruits.index('banana')
print(f"Banana is at index: {position}") # 1
# copy(): Create shallow copy
original = [1, 2, 3]
copy1 = original.copy()
copy2 = original[:] # Alternative
copy3 = list(original) # Another alternative
Checking Membership
fruits = ['apple', 'banana', 'cherry']
# in operator
if 'apple' in fruits:
print("We have apples!")
if 'orange' not in fruits:
print("No oranges available")
# Check for any or all conditions
numbers = [2, 4, 6, 8, 10]
all_even = all(n % 2 == 0 for n in numbers)
print(f"All even: {all_even}") # True
has_large = any(n > 15 for n in numbers)
print(f"Has number > 15: {has_large}") # False
Looping Through Lists
fruits = ['apple', 'banana', 'cherry']
# Basic loop
for fruit in fruits:
print(fruit)
# With index using enumerate
for index, fruit in enumerate(fruits):
print(f"{index}: {fruit}")
# Start counting from 1
for position, fruit in enumerate(fruits, start=1):
print(f"{position}. {fruit}")
# Loop with range and index
for i in range(len(fruits)):
print(f"fruits[{i}] = {fruits[i]}")
# Reverse iteration
for fruit in reversed(fruits):
print(fruit)
List Comprehensions
Compact way to create lists based on existing lists or ranges.
# Basic comprehension
squares = [x**2 for x in range(10)]
print(squares) # [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
# With condition
even_squares = [x**2 for x in range(10) if x % 2 == 0]
print(even_squares) # [0, 4, 16, 36, 64]
# Transform strings
names = ['alice', 'bob', 'charlie']
capitalized = [name.upper() for name in names]
print(capitalized) # ['ALICE', 'BOB', 'CHARLIE']
# Nested comprehension
matrix = [[i*j for j in range(1, 4)] for i in range(1, 4)]
print(matrix)
# [[1, 2, 3], [2, 4, 6], [3, 6, 9]]
# Filter and transform
numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
doubled_evens = [x * 2 for x in numbers if x % 2 == 0]
print(doubled_evens) # [4, 8, 12, 16, 20]
What are Tuples?
A tuple is an ordered, immutable (unchangeable) collection.
# Creating tuples
fruits_tuple = ('apple', 'banana', 'cherry')
numbers_tuple = (1, 2, 3, 4, 5)
mixed_tuple = (1, 'hello', 3.14, True)
# Single element tuple (note the comma!)
single = (42,) # Tuple with one element
not_tuple = (42) # This is just an integer!
# Without parentheses (tuple packing)
point = 10, 20, 30
print(type(point)) # <class 'tuple'>
# Empty tuple
empty = ()
Key Characteristics of Tuples
- Ordered: Items maintain their position
- Immutable: Cannot be modified after creation
- Allow duplicates: Can contain the same value multiple times
- Indexed: Access items by position (starting at 0)
- Faster than lists: Due to immutability
- Can be dictionary keys: Because they're hashable
Accessing Tuple Elements
point = (10, 20, 30, 40, 50)
# Indexing (same as lists)
print(point[0]) # 10
print(point[-1]) # 50
# Slicing (same as lists)
print(point[1:4]) # (20, 30, 40)
print(point[:3]) # (10, 20, 30)
print(point[::2]) # (10, 30, 50)
# Tuple unpacking
x, y, z = (10, 20, 30)
print(f"x={x}, y={y}, z={z}")
# Unpacking with * (rest)
first, *middle, last = (1, 2, 3, 4, 5)
print(f"First: {first}")
print(f"Middle: {middle}") # [2, 3, 4]
print(f"Last: {last}")
Tuple Methods (Limited Due to Immutability)
numbers = (1, 2, 3, 2, 4, 2, 5)
# count(): Count occurrences
count_of_2 = numbers.count(2)
print(f"Number of 2s: {count_of_2}") # 3
# index(): Find first occurrence
position = numbers.index(4)
print(f"4 is at index: {position}") # 4
# Length
print(f"Length: {len(numbers)}")
# Check membership
if 3 in numbers:
print("3 is in the tuple")
Why Use Tuples?
1. Immutability Guarantees Data Safety
# Coordinates shouldn't change
point = (10, 20)
# This would cause an error:
# point[0] = 15 # TypeError: 'tuple' object does not support item assignment
# Use tuples for constants
RGB_RED = (255, 0, 0)
RGB_GREEN = (0, 255, 0)
RGB_BLUE = (0, 0, 255)
2. As Dictionary Keys
# Tuples can be dictionary keys; lists cannot
locations = {}
locations[(0, 0)] = "Origin"
locations[(10, 20)] = "Point A"
locations[(-5, 15)] = "Point B"
print(locations[(0, 0)]) # "Origin"
# Lists cannot be keys:
# locations[[1, 2]] = "Won't work" # TypeError
3. Multiple Return Values from Functions
def get_min_max(numbers):
"""Return both minimum and maximum"""
return min(numbers), max(numbers)
# Returns a tuple
result = get_min_max([5, 2, 8, 1, 9])
print(result) # (1, 9)
# Unpack immediately
minimum, maximum = get_min_max([5, 2, 8, 1, 9])
print(f"Min: {minimum}, Max: {maximum}")
4. Performance
import sys
list_example = [1, 2, 3, 4, 5]
tuple_example = (1, 2, 3, 4, 5)
# Tuples use less memory
print(f"List size: {sys.getsizeof(list_example)} bytes")
print(f"Tuple size: {sys.getsizeof(tuple_example)} bytes")
# Tuples are faster to create and iterate
Converting Between Lists and Tuples
# List to tuple
my_list = [1, 2, 3, 4, 5]
my_tuple = tuple(my_list)
print(my_tuple) # (1, 2, 3, 4, 5)
# Tuple to list
my_tuple = (1, 2, 3, 4, 5)
my_list = list(my_tuple)
print(my_list) # [1, 2, 3, 4, 5]
# Modify tuple by converting
original_tuple = (1, 2, 3)
temp_list = list(original_tuple)
temp_list.append(4)
new_tuple = tuple(temp_list)
print(new_tuple) # (1, 2, 3, 4)
Practical Examples
Example 1: Shopping Cart
# Using list for mutable shopping cart
cart = []
# Add items
cart.append({'name': 'Apple', 'price': 0.5, 'qty': 5})
cart.append({'name': 'Banana', 'price': 0.3, 'qty': 10})
cart.append({'name': 'Orange', 'price': 0.6, 'qty': 3})
# Calculate total
total = 0
for item in cart:
item_total = item['price'] * item['qty']
print(f"{item['name']}: ${item_total:.2f}")
total += item_total
print(f"\nTotal: ${total:.2f}")
# Remove an item
cart.remove(cart[1]) # Remove banana
Example 2: Student Grade Management
# Store student grades
students = [
{'name': 'Alice', 'grades': [85, 92, 78, 90]},
{'name': 'Bob', 'grades': [75, 88, 82, 86]},
{'name': 'Charlie', 'grades': [95, 89, 93, 91]}
]
# Calculate averages
for student in students:
grades = student['grades']
average = sum(grades) / len(grades)
print(f"{student['name']}: {average:.1f}")
# Find top student
best_student = max(students, key=lambda s: sum(s['grades']) / len(s['grades']))
print(f"\nTop student: {best_student['name']}")
Example 3: Coordinate System
# Using tuples for immutable coordinates
points = [
(0, 0), # Origin
(10, 20), # Point A
(15, 25), # Point B
(5, 30) # Point C
]
# Calculate distances from origin
import math
for point in points:
x, y = point
distance = math.sqrt(x**2 + y**2)
print(f"Point {point}: distance = {distance:.2f}")
# Find furthest point
furthest = max(points, key=lambda p: p[0]**2 + p[1]**2)
print(f"Furthest point: {furthest}")
Example 4: Data Processing Pipeline
# Process list of numbers
data = [15, 23, 8, 42, 16, 31, 27, 4, 19]
# Filter: Keep only even numbers
even_numbers = [x for x in data if x % 2 == 0]
print(f"Even numbers: {even_numbers}")
# Map: Square all numbers
squared = [x**2 for x in data]
print(f"Squared: {squared}")
# Reduce: Find sum
total = sum(data)
print(f"Sum: {total}")
# Chain operations
result = sum([x**2 for x in data if x % 2 == 0])
print(f"Sum of squares of evens: {result}")
Example 5: Nested Lists (Matrix Operations)
# Represent a matrix
matrix = [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9]
]
# Print matrix
for row in matrix:
print(row)
# Access elements
print(f"Element at [1][2]: {matrix[1][2]}") # 6
# Sum all elements
total = sum(sum(row) for row in matrix)
print(f"Sum of all elements: {total}")
# Transpose matrix
transposed = [[matrix[j][i] for j in range(len(matrix))]
for i in range(len(matrix[0]))]
print("\nTransposed:")
for row in transposed:
print(row)
Common Patterns
Pattern 1: Find Maximum/Minimum
numbers = [15, 23, 8, 42, 16, 31, 27]
# Using built-in functions
maximum = max(numbers)
minimum = min(numbers)
print(f"Max: {maximum}, Min: {minimum}")
# Manual approach
max_val = numbers[0]
for num in numbers:
if num > max_val:
max_val = num
print(f"Maximum: {max_val}")
Pattern 2: Remove Duplicates
# Remove duplicates while preserving order
numbers = [1, 2, 3, 2, 4, 3, 5, 1]
# Using set (loses order)
unique = list(set(numbers))
# Preserving order
unique_ordered = []
for num in numbers:
if num not in unique_ordered:
unique_ordered.append(num)
print(f"Unique (ordered): {unique_ordered}")
Pattern 3: Flatten Nested List
# Flatten list of lists
nested = [[1, 2, 3], [4, 5], [6, 7, 8, 9]]
# Using list comprehension
flat = [item for sublist in nested for item in sublist]
print(f"Flattened: {flat}")
# Using extend
flat = []
for sublist in nested:
flat.extend(sublist)
print(f"Flattened: {flat}")
Common Mistakes
Mistake 1: Confusing append and extend
# append adds the entire object
my_list = [1, 2, 3]
my_list.append([4, 5])
print(my_list) # [1, 2, 3, [4, 5]] - nested!
# extend adds individual items
my_list = [1, 2, 3]
my_list.extend([4, 5])
print(my_list) # [1, 2, 3, 4, 5] - flat!
Mistake 2: Modifying List While Iterating
# WRONG: Don't modify list during iteration
numbers = [1, 2, 3, 4, 5]
for num in numbers:
if num % 2 == 0:
numbers.remove(num) # Dangerous!
# CORRECT: Create new list
numbers = [1, 2, 3, 4, 5]
odd_numbers = [num for num in numbers if num % 2 != 0]
Mistake 3: Forgetting Tuple Comma
# This is NOT a tuple!
not_tuple = (42)
print(type(not_tuple)) # <class 'int'>
# This IS a tuple
is_tuple = (42,)
print(type(is_tuple)) # <class 'tuple'>
Practice Exercises
Exercise 1: List Statistics
Create a program that:
- Takes a list of numbers
- Calculates mean, median, and mode
- Finds numbers above/below average
Exercise 2: Todo List Manager
Build a simple todo list with:
- Add task
- Remove task
- Mark task as complete
- Display all tasks
Exercise 3: Student Records
Create a system to:
- Store student records (name, grades tuple)
- Calculate GPA for each student
- Find honor roll students (GPA > 3.5)
- Sort students by GPA
Sample Solutions
Exercise 1:
def calculate_statistics(numbers):
# Mean
mean = sum(numbers) / len(numbers)
# Median
sorted_nums = sorted(numbers)
n = len(sorted_nums)
median = sorted_nums[n//2] if n % 2 == 1 else (sorted_nums[n//2-1] + sorted_nums[n//2]) / 2
# Mode
from collections import Counter
counts = Counter(numbers)
mode = counts.most_common(1)[0][0]
# Above/below average
above = [n for n in numbers if n > mean]
below = [n for n in numbers if n < mean]
return {
'mean': mean,
'median': median,
'mode': mode,
'above_avg': len(above),
'below_avg': len(below)
}
numbers = [15, 23, 8, 42, 16, 31, 27, 23, 19]
stats = calculate_statistics(numbers)
print(stats)
Key Takeaways
Lists:
- Mutable, ordered collections
- Use for data that changes
- Rich set of methods (append, remove, sort, etc.)
- Use square brackets
[]
Tuples:
- Immutable, ordered collections
- Use for data that shouldn't change
- Faster and more memory-efficient
- Can be dictionary keys
- Use parentheses
()
When to Use Which:
- List: Shopping cart, todo list, game scores
- Tuple: Coordinates, RGB colors, function returns, dictionary keys
What's Next?
Now that you understand lists and tuples:
- Dictionaries and Sets - Key-value pairs and unique collections
- Loops - Iterate through these collections
- Functions - Process lists and tuples
Lists and tuples are the foundation of data storage in Python. Master these structures and you'll be able to organize and manipulate data efficiently!
