Step 06 of 10

Lists & dictionaries

Store collections of values in lists and dictionaries, loop over them, and model real data such as a shopping cart or a word count.

18 min 8 sections

Real programs rarely deal with one value at a time. A shopping cart has many items, a class has many students, a text has many words. Python's two workhorse collections handle almost all of this: the list, an ordered sequence of values, and the dictionary, which looks values up by a key. This lesson teaches both, the everyday operations on each, and how to combine them to model real data.

Lists: ordered collections

A list holds values in order, inside square brackets:

python
fruits = ["apple", "banana", "cherry"]
scores = [88, 92, 75, 100]
empty = []

print(len(fruits))     # 3
print(fruits[0])       # apple   (indexes start at 0)
print(fruits[-1])      # cherry  (negative counts from the end)
print(scores[1:3])     # [92, 75]  slicing works like strings
print("banana" in fruits)   # True

Unlike strings, lists are mutable: you can change them in place.

python
fruits[0] = "apricot"          # replace an item
fruits.append("date")          # add to the end
fruits.insert(1, "blueberry")  # insert at a position
fruits.remove("banana")        # remove the first matching value
last = fruits.pop()            # remove and return the last item
print(fruits)                  # ['apricot', 'blueberry', 'cherry']
print(last)                    # date

Asking for an index that doesn't exist is an error, not an empty answer:

python
fruits[10]     # IndexError: list index out of range

Looping over lists

A for loop visits each item in order, which is how you'll process lists nearly every time:

python
prices = [4.99, 12.50, 3.25]
total = 0
for price in prices:
    total += price
print(f"Total: ${total:.2f}")    # Total: $20.74

When you need the position as well, use enumerate, which gives you pairs of (index, item):

python
for position, fruit in enumerate(["apple", "banana", "cherry"], start=1):
    print(f"{position}. {fruit}")
text
1. apple
2. banana
3. cherry

Python has built-ins for the common calculations, so you often don't need a loop at all:

python
scores = [88, 92, 75, 100]
print(sum(scores), min(scores), max(scores))   # 355 75 100
print(sum(scores) / len(scores))               # 88.75
print(sorted(scores))                          # [75, 88, 92, 100]  a new sorted list
scores.sort(reverse=True)                      # sorts the list itself, largest first
print(scores)                                  # [100, 92, 88, 75]

sorted(x) returns a new list and leaves x alone; x.sort() changes x and returns None. Mixing them up (scores = scores.sort()) is a classic bug that leaves you with None.

Building a new list from an old one

A very common job is "make a list of X from a list of Y". The loop version:

python
names = ["ana", "ben", "cy"]
capitalised = []
for name in names:
    capitalised.append(name.capitalize())

Python has a compact form for exactly this, a list comprehension:

python
capitalised = [name.capitalize() for name in names]       # ['Ana', 'Ben', 'Cy']
passed = [s for s in [88, 45, 92, 51] if s >= 50]         # [88, 92, 51]

Read it as "the list of name.capitalize() for each name in names". Use comprehensions for simple transformations and filters; switch back to a loop when it gets complicated.

Dictionaries: looking things up by key

A list finds items by position. Often you want to find them by a name instead: a phone number by person, a price by product. A dictionary (dict) stores key–value pairs in curly braces:

python
prices = {"apple": 0.50, "bread": 2.20, "milk": 1.10}

print(prices["bread"])      # 2.2
prices["eggs"] = 3.00       # add a new pair
prices["milk"] = 1.25       # change an existing value
del prices["apple"]         # remove a pair
print("milk" in prices)     # True  (checks keys, not values)
print(len(prices))          # 3

Looking up a key that doesn't exist raises a KeyError. When a key might be missing, use .get, which returns a default instead:

python
print(prices.get("cheese"))        # None
print(prices.get("cheese", 0))     # 0

Keys must be unique (assigning to an existing key replaces its value) and are usually strings or numbers. Values can be anything, including lists and other dictionaries.

Loop over a dictionary's pairs with .items():

python
for item, price in prices.items():
    print(f"{item:<8} ${price:.2f}")
text
bread    $2.20
milk     $1.25
eggs     $3.00

Dictionaries remember the order in which keys were added.

The counting pattern

Counting how often things occur is one of the most common uses of a dictionary:

python
votes = ["red", "blue", "red", "green", "red", "blue"]

counts = {}
for colour in votes:
    counts[colour] = counts.get(colour, 0) + 1

print(counts)    # {'red': 3, 'blue': 2, 'green': 1}

For each vote, look up the current count (0 if this is the first time), add one, and store it back.

Tuples and sets, briefly

Two more collections you'll meet:

  • A tuple is like a list that can't be changed, written with parentheses: point = (3, 4). Use it for small fixed groups of values, such as coordinates or a function returning two things (return total, count). You can unpack it: x, y = point.
  • A set holds unique values with no order: {"red", "blue"}. Adding a duplicate does nothing, and checking membership with in is very fast. set(votes) gives you the distinct values of a list.

Modelling real data: combining collections

Real data is usually a list of records, and each record is a dictionary:

python
cart = [
    {"name": "Notebook", "price": 3.50, "quantity": 4},
    {"name": "Pen", "price": 1.20, "quantity": 10},
    {"name": "Backpack", "price": 35.00, "quantity": 1},
]

total = 0
for item in cart:
    line_total = item["price"] * item["quantity"]
    total += line_total
    print(f"{item['name']:<10} {item['quantity']:>3} × ${item['price']:>6.2f} = ${line_total:>6.2f}")
print(f"{'Total':<29} ${total:>6.2f}")
text
Notebook     4 × $  3.50 = $ 14.00
Pen         10 × $  1.20 = $ 12.00
Backpack     1 × $ 35.00 = $ 35.00
Total                         $ 61.00

This shape, a list of dictionaries, is exactly what you'll get from files, spreadsheets and web APIs later on, so it's worth getting comfortable with now. Inside an f-string that uses double quotes, use single quotes for dictionary keys, as above.

One trap: two names, one list

Assigning a list to a second variable doesn't copy it. Both names refer to the same list:

python
original = [1, 2, 3]
alias = original
alias.append(4)
print(original)     # [1, 2, 3, 4]  surprise!

To get an independent copy, ask for one:

python
copy = original.copy()     # or list(original), or original[:]
copy.append(5)
print(original)            # [1, 2, 3, 4]  unchanged

The same applies when you pass a list into a function: the function receives the same list, so if it calls .append the caller sees the change. Usually that's what you want; just be aware of it.

Practice

Write wordcount.py that analyses a piece of text:

  1. Store a paragraph of text in a variable (paste anything you like, a few sentences long).
  2. Split it into words with text.lower().split(), and remove punctuation from each word with word.strip(".,!?;:\"'()"). Skip any word that becomes empty.
  3. Count how often each word appears, using a dictionary.
  4. Print the total number of words, the number of distinct words, and the 5 most common words with their counts.

For step 4, this sorts a dictionary's pairs by count, highest first: sorted(counts.items(), key=lambda pair: pair[1], reverse=True). The key= part tells sorted what to compare: here, the second element of each pair.

Show solution
python
# wordcount.py
text = """The quick brown fox jumps over the lazy dog. The dog sleeps,
and the fox runs away. A quick fox is a happy fox!"""

counts = {}
total = 0
for raw in text.lower().split():
    word = raw.strip(".,!?;:\"'()")
    if not word:
        continue
    total += 1
    counts[word] = counts.get(word, 0) + 1

print(f"Total words:    {total}")
print(f"Distinct words: {len(counts)}")
print("Most common:")

ranked = sorted(counts.items(), key=lambda pair: pair[1], reverse=True)
for word, count in ranked[:5]:
    print(f"  {word:<8} {count}")
text
Total words:    24
Distinct words: 15
Most common:
  the      4
  fox      4
  quick    2
  dog      2
  a        2

split() with no argument splits on any whitespace, including line breaks. if not word skips strings that became empty after stripping (an empty string counts as false). ranked[:5] slices the first five pairs, and each pair unpacks into word, count in the loop. When two words have the same count, sorted keeps them in the order they first appeared, because Python's sort is stable.

Key takeaways

  • A list is an ordered, changeable sequence: index from 0, append, insert, remove, pop, and loop with for or enumerate.
  • sorted() returns a new list; .sort() changes the list and returns None.
  • A dictionary maps unique keys to values: look up with d[key] or d.get(key, default), loop with .items().
  • counts[k] = counts.get(k, 0) + 1 is the counting pattern; a list of dictionaries is the standard shape for records.
  • Assigning a list to another name doesn't copy it; use .copy() when you need an independent list.

Check yourself

Quiz

0/4 correct · 4 left

  1. 1.numbers = [5, 3, 8]; result = numbers.sort(). What is result?

  2. 2.stock = {"pens": 10}. Which expression returns 0 instead of raising an error for a missing key?

  3. 3.a = [1, 2]; b = a; b.append(3); print(a). What is printed?

  4. 4.You need to look up a student's grade quickly by their student ID. Which collection fits best?

Finished reading?

Mark it complete to fill in your roadmap.