All 3.1 28 min read 10 question quiz 17 exam marks

Dictionaries, Files and Error Handling

Storing structured data, saving it between runs, and writing programs that survive things going wrong.

Dictionaries

A dictionary stores pairs of keys and values. You look a value up by its key rather than by a numeric position, which makes the code far more readable.

Python
student = {
    "name": "Aisha",
    "year": 11,
    "grades": [8, 9, 7],
    "active": True
}

print(student["name"])          # Aisha
student["year"] = 12            # change a value
student["house"] = "Blue"       # add a new pair
del student["active"]           # remove a pair

Safe access

Python
print(student.get("email"))                 # None, no crash
print(student.get("email", "not given"))    # a default value
print("name" in student)                    # True

Using square brackets on a missing key raises a KeyError. Use get() when the key might not be there.

Looping

Python
for key in student:
    print(key, "=", student[key])

for key, value in student.items():
    print(f"{key}: {value}")

print(list(student.keys()))
print(list(student.values()))

A list of dictionaries

This is how most real data is shaped.

Python
students = [
    {"name": "Aisha", "mark": 92},
    {"name": "Ben", "mark": 68},
    {"name": "Chloe", "mark": 77},
]

for s in students:
    print(f"{s['name']:<8} {s['mark']}")

best = max(students, key=lambda s: s["mark"])
print("Top:", best["name"])

average = sum(s["mark"] for s in students) / len(students)
print(f"Average: {average:.1f}")

Tuples and sets

Python
point = (3, 7)              # a tuple, cannot be changed
x, y = point                # unpacking

unique = {1, 2, 2, 3, 3}    # a set, duplicates removed
print(unique)               # {1, 2, 3}
A dictionary is a cabinet of labelled drawersA Python dictionary drawn as a filing cabinet. Each drawer has a label, which is the key, and holds one value: the drawer labelled name holds Asha, the drawer labelled age holds 15, and the drawer labelled form, added by the second line of code, holds 10B. To find a value you ask for it by key, so student with the key age gives 15, and the test form in student is True because a drawer with that label exists. A fourth drawer labelled club is shown dashed because it has not been added: asking for a key that is not there is an error. A list is found by position, scores at index 2, but a dictionary is found by key, student at key age, and the order of the drawers does not matter.dict.py1student = {"name": "Asha", "age": 15}2student["form"] = "10B"3print(student["age"])4print("form" in student)output15TrueList or dictionary?listfind by positionscores[2]dictionaryfind by keystudent["age"]a key is a label you choose, so the order does not mattername"Asha"age15form"10B"clubnot here123
  1. Each drawer has a key for a label and one value inside it.
  2. Assigning to a new key adds a drawer, here form: "10B".
  3. Ask for a value by its key, and in tests whether a key exists.
Use a list when position matters and a dictionary when a name does.

Files

Writing and reading

Python
# Write, which ERASES the file first
with open("scores.txt", "w") as file:
    file.write("Aisha,92\n")
    file.write("Ben,68\n")

# Append, which adds to the end
with open("scores.txt", "a") as file:
    file.write("Chloe,77\n")

# Read line by line
with open("scores.txt", "r") as file:
    for line in file:
        name, mark = line.strip().split(",")
        print(f"{name} scored {mark}")

# Read the whole file
with open("scores.txt", "r") as file:
    contents = file.read()

# Read into a list of lines
with open("scores.txt", "r") as file:
    lines = file.readlines()

with open(...) closes the file automatically, even if an error happens. Always use it.

ModeMeaning
"r"Read. Fails if the file does not exist.
"w"Write. Creates the file, and erases anything already in it.
"a"Append. Creates if needed, adds to the end.
Write mode destroys the file

If a question or a program needs to add a record without losing existing data, the mode must be "a".

CSV files

Python
import csv

with open("students.csv", "w", newline="") as file:
    writer = csv.writer(file)
    writer.writerow(["Name", "Mark"])
    writer.writerow(["Aisha", 92])

with open("students.csv", "r") as file:
    reader = csv.reader(file)
    next(reader)                     # skip the header row
    for row in reader:
        print(row[0], row[1])

JSON, for saving structured data

Python
import json

data = {"players": ["Aisha", "Ben"], "high_score": 4200}

with open("save.json", "w") as file:
    json.dump(data, file)

with open("save.json", "r") as file:
    loaded = json.load(file)

print(loaded["high_score"])

JSON is ideal for saving dictionaries and lists exactly as they are, which makes it the natural way to save game state or settings.

Reading, writing and appending to a text fileThree ways to open a text file, one card each. Opening with mode r reads the file: the program looks at the lines, nothing in the file changes, and it is an error if the file does not exist. Opening with mode w writes: it creates the file if it is missing, but if it exists everything in it is erased first, so a file that held two lines ends up holding only the new line. Opening with mode a appends: the new line is added to the end and the old lines are kept. The code below uses the with statement, which closes the file automatically, and writes the line Tia comma 51 followed by a newline character. Always close a file, because unwritten data may stay in a buffer and never reach the disk."r" readbeforeAsha,42Tom,37"w" writebeforeAsha,42Tom,37"a" appendbeforeAsha,42Tom,37programreads each linethe file is not changederror if it does not existTia,51erases what was therecreates the file if missingAsha,42Tom,37Tia,51adds to the endkeeps what was theresave.py1with open("scores.txt", "a") as f:2    f.write("Tia,51\n")with closes the file for you\n starts a new linea is safer than w for addingalways close a file, or the last lines may never reach the disk1234
  1. r reads. The file is only looked at, and it must already exist.
  2. w writes. Everything already in the file is erased first.
  3. a appends. New lines go on the end and the old ones are kept.
  4. with closes the file for you, and \n ends a line.
If you mean to add to a file, open it with a. Opening it with w by mistake wipes it.

Error handling

A robust program does not crash when something goes wrong. It handles it.

Python
try:
    age = int(input("Enter your age: "))
    print(f"Next year you will be {age + 1}")
except ValueError:
    print("That was not a whole number.")

Handling several kinds of error

Python
try:
    with open("data.txt", "r") as file:
        numbers = [int(line) for line in file]
    print(sum(numbers) / len(numbers))

except FileNotFoundError:
    print("The file does not exist yet.")
except ValueError:
    print("The file contains something that is not a number.")
except ZeroDivisionError:
    print("The file is empty.")
else:
    print("Everything worked.")
finally:
    print("Finished.")
  • except runs when that error occurs
  • else runs only if there was no error
  • finally runs either way, which is useful for tidying up

Errors worth catching

ErrorWhen
ValueErrorConverting text that is not a number
FileNotFoundErrorOpening a file that does not exist
ZeroDivisionErrorDividing by zero
KeyErrorLooking up a key that is not in a dictionary
IndexErrorUsing an index beyond the end of a list
TypeErrorAn operation between incompatible types
Catch specific errors, not everything

A bare except: hides real bugs, including typos in your own code, and makes problems far harder to find. Name the error you expect.

A robust input function

Python
def get_int(prompt, low, high):
    while True:
        try:
            value = int(input(prompt))
            if low <= value <= high:
                return value
            print(f"Please enter a number between {low} and {high}.")
        except ValueError:
            print("That is not a whole number.")

This function cannot crash and cannot return an invalid value. That is what robust means.

try and except: catching an error instead of crashingError handling drawn as a safety net under a tightrope. The risky code goes in a try block, shown as Pixel on the rope: it asks for a number and then divides 100 by it. If something goes wrong, the program does not crash: it falls into the net, which is the matching except block. There are three runs. If the user types the letters abc, int fails with a ValueError, the except ValueError block runs and prints Numbers only. If the user types 0, the division fails with a ZeroDivisionError and the program prints Cannot divide by zero. If the user types 4 nothing goes wrong, the except blocks are skipped and the program prints 25.0.safe.py1try:2    n = int(input("Number: "))3    print(100 / n)4except ValueError:5    print("Numbers only")6except ZeroDivisionError:7    print("Cannot divide by zero")the try blockexcept catches the fallThree runs"abc"ValueErrorNumbers only0ZeroDivisionErrorCannot divide by zero4no error25.01234
  1. try holds the code that might fail.
  2. except ValueError catches a bad conversion, such as int("abc").
  3. except ZeroDivisionError catches a division by zero.
  4. With no error, the except blocks are skipped and the program carries on.
Catch the specific error you expect, and say what went wrong in plain words.

Key terms you must be able to define

Dictionary
A collection storing pairs of keys and values, looked up by key.
Key
The name used to look up a value in a dictionary.
Tuple
An ordered collection that cannot be changed after creation.
Set
An unordered collection with no duplicate values.
with open()
A statement that opens a file and closes it automatically when finished.
Append mode
Opening a file so new data is added to the end without erasing existing content.
CSV
Comma separated values, a simple text format for tabular data.
JSON
A text format for storing structured data such as dictionaries and lists.
Exception
An error raised while a program is running.
try and except
A structure that attempts code and handles an error rather than crashing.

Flashcards

Say the definition out loud before you flip the card. Retrieving it from memory is what builds recall, reading it again is not.

DefineDictionary
AnswerA collection storing pairs of keys and values, looked up by key.
DefineKey
AnswerThe name used to look up a value in a dictionary.
DefineTuple
AnswerAn ordered collection that cannot be changed after creation.
DefineSet
AnswerAn unordered collection with no duplicate values.
Definewith open()
AnswerA statement that opens a file and closes it automatically when finished.
DefineAppend mode
AnswerOpening a file so new data is added to the end without erasing existing content.
DefineCSV
AnswerComma separated values, a simple text format for tabular data.
DefineJSON
AnswerA text format for storing structured data such as dictionaries and lists.

Reach the top grade on this topic

  • Use a dictionary whenever data has named fields, rather than remembering list positions
  • Always use with open() so files close even when something fails
  • Choose append mode whenever existing data must be preserved
  • Catch the specific exception you expect, never a bare except
  • Write input functions that cannot crash and cannot return an invalid value

Mistakes that cost marks here

Avoid these
  • Opening a file in write mode when the existing contents matter.
  • Using square brackets on a dictionary key that might not exist, causing a KeyError.
  • Using a bare except, which hides typos and real bugs.
  • Forgetting to strip the newline character when reading lines from a file.
  • Assuming a file exists, so the program crashes the very first time it runs.
Fun fact

Almost every real program you use stores its data as key and value pairs. Settings files, web APIs, save games and configuration are all essentially dictionaries.

Knowledge check

0 of 10 answered
1What does a dictionary store?
2What does student.get("email") return if there is no email key?
3Which file mode preserves existing content?
4Why use with open(...) rather than open(...)?
5Which error occurs when converting the text 'hello' to an integer?
6What does finally do in a try block?
7Why should you avoid a bare except:?
8What is a tuple?
9What format is best for saving a dictionary to a file so it can be loaded back exactly?
10Which error occurs when you look up a dictionary key that does not exist using square brackets?
Score 0 / 10

Exam-style questions

Five written questions in the style of the real paper. Write a full answer, then let the marker check it against the mark scheme.

17 marks
1State one advantage of using a dictionary rather than a list to store a student's details.2 marks
State

Mark scheme0 / 2
  • LValues are accessed by a meaningful name rather than a numeric position
  • LThis makes the code easier to read and less error prone
Model answer

A dictionary lets each value be accessed by a meaningful key, so writing student["mark"] makes the intention completely clear. With a list you would have to remember that the mark happened to be stored at index 2, which is far harder to read and very easy to get wrong, especially if the order of the fields ever changes.

The marker looks for key phrases. If you said it another way and it is still right, give yourself the mark.
2Explain why the try and except structure is used, and give an example of when it would be needed.4 marks
Explain

Mark scheme0 / 4
  • LIt attempts code that might cause an error
  • LIf the error occurs the except block runs instead of the program crashing
  • LGives a valid example such as converting user input or opening a file
  • LExplains that this makes the program robust
Model answer

The try and except structure is used so a program can attempt something that might fail without crashing if it does. The code inside try is executed, and if it raises the named exception then Python jumps straight to the matching except block instead of stopping the program. A common example is converting user input to a number: if the user types letters, int() raises a ValueError, and without handling it the program would crash and the user would lose their work. With try and except the program can display a clear message and ask again. Handling errors like this is what makes a program robust, which means it continues to behave sensibly even when things go wrong.

The marker looks for key phrases. If you said it another way and it is still right, give yourself the mark.
3Write a program that reads a file called marks.txt containing one number per line and prints the average, handling the case where the file does not exist.5 marks
Write

Mark scheme0 / 5
  • LUses try and except around the file operation
  • LOpens the file for reading
  • LConverts each line into a number
  • LCalculates and prints the average
  • LCatches FileNotFoundError with a helpful message
Model answer

try: with open("marks.txt", "r") as file: marks = [int(line.strip()) for line in file if line.strip()] if len(marks) == 0: print("The file is empty.") else: print(f"Average: {sum(marks) / len(marks):.1f}") except FileNotFoundError: print("marks.txt could not be found.") except ValueError: print("The file contains something that is not a number.") Using with open means the file closes automatically. Each line is stripped of its newline before being converted, and blank lines are skipped. The empty file case is checked separately, because dividing by zero would otherwise raise its own error. Two specific exceptions are caught rather than using a bare except, so genuine bugs in the code are not hidden.

The marker looks for key phrases. If you said it another way and it is still right, give yourself the mark.
4Explain the difference between opening a file in write mode and append mode.3 marks
Explain

Mark scheme0 / 3
  • LWrite mode erases everything already in the file
  • LAppend mode adds to the end and keeps existing content
  • LAppend should be used when previous data must be kept
Model answer

Opening a file in write mode empties it completely before anything is written, so every piece of data previously stored in that file is lost. Opening in append mode leaves the existing contents intact and adds anything written to the end. Write mode is appropriate when the entire contents are being replaced, such as saving a complete updated set of records. Append mode is essential whenever a single new record is being added to data that must be preserved, for example writing one more high score to a file that already contains a list of them.

The marker looks for key phrases. If you said it another way and it is still right, give yourself the mark.
5Explain why catching a specific exception is better than using a bare except that catches everything.3 marks
Explain

Mark scheme0 / 3
  • LA bare except catches every error including ones you did not anticipate
  • LThis hides genuine bugs such as typos in variable names
  • LCatching a specific exception means only the expected problem is handled and other errors are still reported
Model answer

A bare except catches absolutely every exception, including ones the programmer never anticipated. That means a genuine bug elsewhere in the try block, such as a misspelled variable name raising a NameError, is silently swallowed and replaced with whatever message the except block prints. The program appears to handle the situation while actually hiding a real fault, which can take a very long time to track down. Naming the specific exception, such as except ValueError, means only the problem you actually expected is handled, and any other error still stops the program and reports itself properly so it can be found and fixed.

The marker looks for key phrases. If you said it another way and it is still right, give yourself the mark.
Machine mark 0 / 17