Browse this section
Browse these items

All writing

Details and outline
Kind
Essay
Published
27 October 2026
Length
4 min read
Authorship
Created, drafted, and interpreted by Claude
Model
Claude Sonnet 5.5

AI disclaimer: this page was written for the site owner to read occasionally. AI can make mistakes, so the content may be inaccurate. Please read it with caution. The site owner does not recommend making any decision based on AI-generated content.

Essay

Learning Python, Part 5: Tuples, Dictionaries, Sets and Exceptions

Study notes on tuples, dictionaries, sets, sorting with keys, lambda, and handling errors with try and except. Written entirely by an AI model.

Lists are not the only way to hold a collection. This part covers three more, how to sort them, and how to deal with the errors that real input causes.

Tuples

A tuple is an ordered, immutable sequence written with brackets: point = (3, 4). It supports indexing, slicing and looping like a list, but you cannot change it. That makes it a good fit for a fixed bundle of related values, such as a name and a score.

Unpacking assigns each part to its own name:

name, score = ("Ana", 91)

A one-item tuple needs a trailing comma, (5,). Without it, (5) is just the number 5 in brackets.

Dictionaries

A dictionary maps keys to values. Lookup by key is fast, and keys must be unique and immutable (strings, numbers, tuples).

stock = {"tea": 12, "rice": 5}
stock["jam"] = 3             # add a key
stock["tea"] += 1            # update a value
print(stock["tea"])          # 13
print("salt" in stock)       # False

Reading a missing key with stock["salt"] raises KeyError. The method get gives a default instead:

print(stock.get("salt", 0))  # 0

Looping gives the keys. Use .items() for key and value together:

for item, qty in stock.items():
    print(f"{item}: {qty}")

Other everyday methods: keys(), values(), pop(key) and del stock[key].

Counting with a dictionary

Counting how often things occur is the most common dictionary job:

found = ["umbrella", "scarf", "umbrella", "keys", "umbrella", "scarf"]
counts = {}
for thing in found:
    counts[thing] = counts.get(thing, 0) + 1
print(counts)      # {'umbrella': 3, 'scarf': 2, 'keys': 1}

counts.get(thing, 0) + 1 means “the current count, or 0 if this is the first time, plus one”.

Sets

A set holds unique items with no order. Adding something twice does nothing.

morning = {"Ana", "Ben", "Cyd"}
evening = {"Ben", "Dee"}

morning & evening     # {'Ben'}                 in both
morning | evening     # all four names          in either
morning - evening     # {'Ana', 'Cyd'}          only in morning

An easy way to remove duplicates from a list is set(items). The result has no particular order, so wrap it in sorted() if you need one. {} on its own makes an empty dictionary, not an empty set. Write set() for that.

Sorting

sorted(items) returns a new sorted list, and items.sort() sorts a list in place. Both accept two options:

  • reverse=True for descending order.
  • key=function, where each item is passed to the function and the results decide the order.
names = ["maya", "Zed", "al", "Bea"]
sorted(names)                       # ['Bea', 'Zed', 'al', 'maya']
sorted(names, key=str.lower)        # ['al', 'Bea', 'maya', 'Zed']
sorted(names, key=len)              # ['al', 'Zed', 'Bea', 'maya']

A lambda is a small unnamed function. It is handy for keys:

games = [("chess", 4), ("go", 9), ("ludo", 4)]
games.sort(key=lambda g: g[1], reverse=True)

Sorting by two things

Tuples compare left to right, so a key can return a tuple. To sort numbers from high to low and ties alphabetically, negate the number:

games.sort(key=lambda g: (-g[1], g[0]))
# [('go', 9), ('chess', 4), ('ludo', 4)]

Another method relies on stability: Python’s sort keeps equal items in their existing order. Sort by the tie-breaker first, then by the main key.

games.sort()                                    # alphabetical first
games.sort(key=lambda g: g[1], reverse=True)    # then by score

The results match, but the single tuple key is easier to reason about.

map(function, items) applies a function to every item, and filter(function, items) keeps those where the function is true. Both give lazy results, so wrap them in list(...) to see them. A list comprehension often reads better: [g[0] for g in games if g[1] > 4].

Exceptions

Some failures cannot be prevented by checking first: a file that is not there, a user who types abc where a number is needed. Python signals them with exceptions, and try and except let you respond.

def read_age(text):
    try:
        return int(text)
    except ValueError:
        return None

Rules of thumb:

  • Name the exception you expect. A bare except: also hides typos and keyboard interrupts.
  • Keep the try block small: only the line that can fail.
  • You can list several: except (ValueError, IndexError):.
  • An optional else block runs when nothing went wrong, and finally always runs.
  • raise ValueError("age must be positive") raises one yourself.

The common types: ValueError (right type, bad value), TypeError (wrong type), KeyError (missing dictionary key), IndexError (position out of range), ZeroDivisionError and OSError (file problems).

Ask until it’s valid

def ask_number(prompt):
    while True:
        try:
            return float(input(prompt))
        except ValueError:
            print("Please type a number.")

The loop only ends when return happens, which only happens when float succeeded. That small structure appears in a great many programs.

Check first, or catch?

Both styles are fine. Checking first (if key in stock) suits conditions you expect often. Catching suits failures that are rare or hard to predict. For files, catching OSError is better, because the file can disappear between a check and the open.

Where to practise

In Set A, “The lantern contest podium” uses a dictionary and a two-part sort key. In Set B, “The restock list” does the same with tuples as values, and “Loading the pantry list” practises exceptions. Part 6 finishes with recursion, searching and classes.