Learn AI
~40 minIn progress

Phase 1 · Programming Fundamentals

Files & Errors

Read and write text files safely, and handle failures with try/except.

~40 min4 sections2 exercisesQuiz · pass 4/5
On this page
  1. 01Writing and reading text files
  2. 02Paths and useful patterns
  3. 03try / except / else / finally
  4. 04Raising your own errors
  5. 05Mini challenge: safe logger
  6. 06Try It
  7. 07Quiz

Writing and reading text files

open(path, mode) connects to a file. Common modes: "w" write (creates/overwrites), "a" append, "r" read.

Always prefer a with block so the file closes automatically—even if something goes wrong.

Write then read
with open("notes.txt", "w", encoding="utf-8") as f:
    f.write("Day 6: files & errors\n")
    f.write("Practice every day.\n")

with open("notes.txt", "r", encoding="utf-8") as f:
    content = f.read()
    print(content)
Read line by line
with open("notes.txt", "r", encoding="utf-8") as f:
    for line in f:
        print(">", line.strip())

Pass encoding="utf-8" so text behaves the same across Windows, macOS, and Linux.

Paths and useful patterns

You can write lists of lines with writelines, or dump structured text one record per line.

Check whether something exists before reading when the file might be missing—or catch the error (next section).

Append and list lines
with open("notes.txt", "a", encoding="utf-8") as f:
    f.write("Appended line.\n")

with open("notes.txt", "r", encoding="utf-8") as f:
    lines = f.readlines()

print(len(lines))
print(lines[0].strip())

Pathlib (from pathlib import Path) is great for real projects; open() + with is enough to start.

try / except / else / finally

Errors raise exceptions. Catch them with try/except so your program can recover or show a clear message.

else runs when no exception happened. finally always runs—useful for cleanup.

Catching errors
text = "42"
try:
    number = int(text)
except ValueError:
    print("Not a number")
else:
    print("Parsed:", number)
finally:
    print("Done attempting parse")
File not found
try:
    with open("missing.txt", "r", encoding="utf-8") as f:
        print(f.read())
except FileNotFoundError:
    print("File does not exist yet—create it first.")

Catch specific exceptions (ValueError, FileNotFoundError). Avoid bare except: — it hides real bugs.

Raising your own errors

Use raise to signal invalid input or impossible states. Callers can catch and handle them.

Good error messages save hours of debugging later.

Validate then raise
def load_score(raw):
    score = int(raw)
    if score < 0 or score > 100:
        raise ValueError("score must be between 0 and 100")
    return score

try:
    print(load_score("150"))
except ValueError as err:
    print("Could not load:", err)

Practice

Mini challenge: safe logger

Write log_message(path, message) that appends message + newline to a file. Write read_log(path) that returns the file text, or "(empty)" if the file is missing. Demo both functions.

challenge starter
def log_message(path, message):
    # TODO: append message + "\n" with encoding utf-8
    pass

def read_log(path):
    # TODO: return file text, or "(empty)" on FileNotFoundError
    pass

log_message("app.log", "server started")
log_message("app.log", "user signed in")
print(read_log("app.log"))
print(read_log("nope.log"))

Interactive

Try It in the browser

Powered by Pyodide

Write three lines to "todo.txt", then read the file and print each line with a leading number (1., 2., 3.).

Output

Errors

Check understanding

Lesson quiz

Score 4/5 or higher to mark this day complete.

1.Why prefer with open(...) as f: over a bare open()?
2.Which mode creates/overwrites a file for writing?
3.Which exception is raised when open() cannot find a file to read?
4.When does a finally block run?
5.Why avoid a bare except: with no exception type?