Skip to content

Chapter 3: Lists, Tuples & Collections - Python's Data Containers Unleashed

Imagine you're organizing a party. Lists are your flexible guest list - people can arrive, leave, swap positions. Tuples? That's your venue address - it doesn't change once set. Dictionaries are your seating chart - each guest has their assigned spot. Sets? The actual people who showed up - no duplicates, no order, just unique individuals.

Let's throw this party.

Lists: Your Shape-Shifting Array

Lists in Python are what arrays wish they could be in other languages. Dynamic sizing? Check. Mixed types? Sure, why not. Negative indexing? You bet.

guests = ["Alice", "Bob", "Charlie"]
chaos = [1, "hello", 3.14, True, None]  # perfectly legal

Indexing: Forward, Backward, and Everywhere

You can access from the front or the back:

fruits = ["apple", "banana", "cherry", "date"]
print(fruits[0])   # "apple" - the beginning
print(fruits[-1])  # "date" - the end
print(fruits[-2])  # "cherry" - second from end

Negative indexing is brilliant. No more fruits[len(fruits)-1] nonsense. Just grab from the back.

Slicing: The Swiss Army Knife

Here's where Python shows off:

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

numbers[2:5]     # [2, 3, 4] - from index 2 to 5 (exclusive)
numbers[:3]      # [0, 1, 2] - first three
numbers[7:]      # [7, 8, 9] - from 7 to end
numbers[-3:]     # [7, 8, 9] - last three
numbers[::2]     # [0, 2, 4, 6, 8] - every second element
numbers[::-1]    # [9, 8, 7, 6, 5, 4, 3, 2, 1, 0] - REVERSED!

That last one? [::-1] to reverse? That's Python flexing. The syntax is [start:stop:step]. Negative step means go backwards.

Want to copy a list? new_list = old_list[:]. Want every third element starting from index 1? list[1::3]. Slicing is poetry.

List Methods: Add, Remove, Rearrange

items = [1, 2, 3]

items.append(4)        # [1, 2, 3, 4] - add to end
items.insert(0, 0)     # [0, 1, 2, 3, 4] - insert at index
items.extend([5, 6])   # [0, 1, 2, 3, 4, 5, 6] - add multiple
items.remove(3)        # removes first occurrence of 3
items.pop()            # removes and returns last item
items.pop(0)           # removes and returns item at index 0

Important distinction: append() adds one item. extend() adds multiple items from an iterable. Don't do items.append([5, 6]) unless you want a nested list.

items.sort()           # sorts in place
items.reverse()        # reverses in place
len(items)             # how many items?
items.count(2)         # how many times does 2 appear?
items.index(4)         # what's the index of 4?

sort() and reverse() modify the list directly. They return None, not a new list. If you want a new sorted list, use sorted(items).

List Comprehensions: The Game Changer

This is where Python goes from "nice language" to "I'm never going back."

Instead of:

squares = []
for i in range(10):
    squares.append(i ** 2)

Write this:

squares = [i ** 2 for i in range(10)]

One line. Clear. Readable. Fast.

You can add conditions:

evens = [x for x in range(20) if x % 2 == 0]
# [0, 2, 4, 6, 8, 10, 12, 14, 16, 18]

Transform and filter:

words = ["hello", "world", "python", "is", "amazing"]
long_upper = [w.upper() for w in words if len(w) > 5]
# ["PYTHON", "AMAZING"]

Nested loops? Yes:

pairs = [(x, y) for x in range(3) for y in range(3)]
# [(0,0), (0,1), (0,2), (1,0), (1,1), (1,2), (2,0), (2,1), (2,2)]

List comprehensions are faster than loops and more Pythonic. Use them. Master them. Love them.

Tuples: The Immutable Twin

Tuples look like lists but use parentheses. The real difference? You can't change them.

coordinates = (10, 20)
rgb = (255, 128, 0)

coordinates[0] = 15  # ERROR! Tuples are immutable

Why would you want immutability?

Reason 1: It's safer. You can't accidentally modify data that shouldn't change.

Reason 2: Tuples can be dictionary keys (lists can't).

Reason 3: They're slightly faster and use less memory.

Tuple Packing and Unpacking

This is where tuples shine:

# Packing
point = 10, 20, 30  # parentheses optional

# Unpacking
x, y, z = point
print(x)  # 10

# Swap variables (no temp variable needed!)
a, b = 5, 10
a, b = b, a  # a is now 10, b is now 5

Functions returning multiple values? They're returning tuples:

def get_dimensions():
    return 1920, 1080  # tuple

width, height = get_dimensions()

This unpacking works with lists too, but tuples are the idiomatic choice for fixed-size collections.

Single Element Tuples: The Comma Matters

not_a_tuple = (5)      # this is just 5 with parentheses
actual_tuple = (5,)    # this is a tuple with one element

That trailing comma? It's what makes it a tuple. Weird, but that's the syntax.

Sets: The Unique-Only Club

Sets store unique values. No duplicates. No guaranteed order.

unique_numbers = {1, 2, 3, 2, 1}  # {1, 2, 3}

Why Use Sets?

Removing duplicates:

items = [1, 2, 2, 3, 4, 4, 5]
unique = list(set(items))  # [1, 2, 3, 4, 5]

Fast membership testing:

allowed_users = {"alice", "bob", "charlie"}

if "alice" in allowed_users:  # O(1) - instant lookup
    grant_access()

Checking if item in list is slow (checks every element). Checking if item in set is instant.

Set Operations: Math Made Practical

a = {1, 2, 3, 4}
b = {3, 4, 5, 6}

a | b  # union: {1, 2, 3, 4, 5, 6}
a & b  # intersection: {3, 4}
a - b  # difference: {1, 2}
a ^ b  # symmetric difference: {1, 2, 5, 6}

These operations are incredibly useful for finding common elements, differences, or combinations.

Dictionaries: The Real MVP

We'll give dictionaries their own chapter because they deserve it. But here's the teaser: if lists are Python's bread and butter, dictionaries are the entire meal.


What You Just Learned: - Lists are flexible, mutable, and slice-able masterpieces - [::-1] reverses anything - List comprehensions replace loops with elegance - Tuples are immutable and perfect for unpacking - Sets eliminate duplicates and enable lightning-fast lookups - Slicing syntax: [start:stop:step]

Coming up: Dictionaries - where Python becomes a superpower. You thought lists were cool? Wait until you see what key-value pairs can do.

Your Challenge: Before moving on, write a list comprehension that takes a string and returns a list of vowels found in it. One line. Go.

# Answer: 
# vowels = [char for char in "hello world" if char in "aeiou"]

Did you get it? If yes, you're ready for dictionaries. If not, read this chapter again. List comprehensions are that important.