livepython.net
CHAPTER 19File Handling
19.4  WITH

Python with open(): Close Files and Handle Errors

The with Statement: Open Files the Safe Way

The with statement opens a file and closes it for you when its block ends. You write with open(...) as f:, put the work in an indented block, and never call close() yourself.

Think of it like a door that closes by itself. You walk through, do what you came for, and when you leave, the door shuts behind you. You can't forget to close it.

The rules

  • with open("notes.txt", "w") as f: opens the file and names it f.
  • End the line with a colon, and indent the block under it, like an if or a for.
  • When the block ends, the file is closed. No f.close() needed.
  • Use with for every file from now on. It's what Python programmers write.
PYTHONedit me
with open("notes.txt", "w") as f:
    f.write("Sunny\n")
    f.write("Rocky\n")

with open("notes.txt") as f:
    text = f.read()

print(text)
OUTPUT
Sunny
Rocky

Two small blocks, no close() anywhere, and the file is still saved and read back properly.

Avoid: forgetting close()

PYTHONedit me
f = open("notes.txt", "w")
f.write("Lucky")

reader = open("notes.txt")
print(len(reader.read()))
reader.close()
OUTPUT
0

The text was written, but the file was never closed, so it wasn't saved yet: the reader finds an empty file. Python keeps your writing in a waiting area (a buffer) and only puts it in the file for sure when the file is closed.

Good: let with close it

PYTHONedit me
with open("notes.txt", "w") as f:
    f.write("Lucky")

with open("notes.txt") as reader:
    print(len(reader.read()))
OUTPUT
5

Common beginner doubt: "Is the text gone when the with block ends?" No. Only the file closes. Anything you stored in a variable inside the block, like text above, is still there afterwards.

with open(...) as f: closes the file for you when the block ends.

your turnFill the gap

Complete the with statement

with open("hello.txt", "w") ? f: f.write("Hello") with open("hello.txt") as f: print(f.read())

It should print: Hello

Which piece makes this code work?
your turnPredict the output

What will this print?

with open("city.txt", "w") as f: f.write("Paris") with open("city.txt") as f: city = f.read() print(city + "!")
Your turn! What will this code show on the screen?

with Closes the File Even After an Error

The best thing about with: it closes the file even when an error happens inside its block. With open() and close() on their own, an error stops the program before it reaches close().

Think of it like a hotel room door that locks itself. Even if you rush out because the fire alarm rings, the door still closes behind you.

The rules

  • An error inside a with block still closes the file, and then the error carries on as usual.
  • Everything written before the error is saved.
  • f.closed is True once a file is closed. It's handy for checking.
PYTHONedit me
try:
    with open("log.txt", "w") as f:
        f.write("Saved before the error\n")
        result = 10 / 0
except ZeroDivisionError:
    print("Something went wrong")

print("Closed:", f.closed)
with open("log.txt") as f:
    print(f.read())
OUTPUT
Something went wrong
Closed: True
Saved before the error

The division by zero stops the block, but with closes the file first. The except from chapter 17 catches the error, and the saved line is safe in the file.

Avoid: close() that never runs

PYTHONedit me
try:
    f = open("log.txt", "w")
    f.write("Saved before the error\n")
    result = 10 / 0
    f.close()
except ZeroDivisionError:
    print("Something went wrong")

print("Closed:", f.closed)
OUTPUT
Something went wrong
Closed: False

The error jumps straight to except, right past f.close(). The file stays open, and its text may never be saved.

What with does for you

Behind the scenes, with works like try and finally from chapter 17: a finally block always runs, error or not. This does the same job, with more typing:

f = open("log.txt", "w")
try:
    f.write("Saved before the error\n")
finally:
    f.close()

That's why with is the way to open files: shorter, and you can't get it wrong.

Common beginner doubt: "Does with stop the error?" No. It only closes the file. The error still happens, and stops the program unless an except catches it.

with closes the file even when an error stops its block. It doesn't catch the error.

your turnPick the right idea

An error happens in the middle of a with block. What happens to the file?

Think about it, then pick one.
your turnType the output

Type what this prints

with open("t.txt", "w") as f: f.write("hi") print(f.closed)
Read the code line by line, then type the output exactly.

Handle FileNotFoundError with try and except

Opening a missing file for reading raises a FileNotFoundError. Put the open() inside try, and an except FileNotFoundError: block can handle it: print a friendly message, or carry on without the file.

Think of it like asking for a book at a library. If it isn't there, the librarian says "sorry, we don't have that one". The library doesn't burn down.

The rules

  • Put the with open(...) that might fail inside try.
  • Catch the exact error: except FileNotFoundError:. A typo or another bug then still shows its own error.
  • Decide what the program does without the file: show a message, or start with an empty list.
PYTHONedit me
with open("notes.txt", "w") as f:
    f.write("Call Rocky at 5")

name = input()
try:
    with open(name) as f:
        print(f.read())
except FileNotFoundError:
    print("No file called", name)
OUTPUT
Call Rocky at 5

Now type notes.text in the Input box and run it again. Instead of a crash, you get: No file called notes.text.

Good: start empty when there's no saved file yet

A program that saves its data has no file the very first time it runs. That's normal, not a problem:

PYTHONedit me
def load_tasks(filename):
    tasks = []
    try:
        with open(filename) as f:
            for line in f:
                tasks.append(line.strip())
    except FileNotFoundError:
        print("No saved tasks yet. Starting fresh.")
    return tasks

tasks = load_tasks("tasks_backup.txt")
print(tasks)
OUTPUT
No saved tasks yet. Starting fresh.
[]

Avoid: catching every error

except: on its own catches every error, even a typo like prnt(f.read()). Then you'd see "No saved tasks yet" when the real problem is a misspelled name. Catch only FileNotFoundError, and other bugs stay easy to spot.

Common beginner doubt: "Do I need try around open() with "w"?" Usually not. Modes "w" and "a" make the file when it's missing, so FileNotFoundError is a reading problem.

Wrap reading in try, and catch FileNotFoundError to handle a missing file.

your turnPredict the output

What will this print?

try: with open("missing.txt") as f: print("Found it") except FileNotFoundError: print("Not found") print("Done")
Your turn! What will this code show on the screen?
your turnFix the code

Make it print: No scores saved yet

It should print: No scores saved yet

with open("old_scores.txt") as f:
    print(f.read())
This code does not work yet. Fix it, then press Run.

Save and Load Data: A Score File Project

To save data like names and scores, write one record per line, with a comma between the parts: Sunny,80. To load it again, read each line and split(",") it back into its parts. A file like this is called a CSV file: comma-separated values.

Think of it like a game's high-score table. Each row has a name and a score, and the game keeps the table in a file so it's still there the next time you play.

The rules

  • Save: f.write(f"{name},{score}\n"): the parts, a comma, and a newline.
  • Load: name, score = line.strip().split(",") unpacks the two parts (as in chapter 14).
  • Everything in a file is text. Turn numbers back with int() when you load them.
  • One function to save, one to load (chapter 15), and the rest of the program stays short.
PYTHONedit me
def save_scores(filename, scores):
    with open(filename, "w") as f:
        for name in scores:
            f.write(f"{name},{scores[name]}\n")

def load_scores(filename):
    scores = {}
    with open(filename) as f:
        for line in f:
            name, score = line.strip().split(",")
            scores[name] = int(score)
    return scores

save_scores("scores.txt", {"Sunny": 80, "Rocky": 95, "Lucky": 72})
loaded = load_scores("scores.txt")
print(loaded)
print("Total:", sum(loaded.values()))
OUTPUT
{'Sunny': 80, 'Rocky': 95, 'Lucky': 72}
Total: 247

The dictionary (chapter 13) goes into the file as three lines of text, and comes back as a dictionary with real numbers in it.

Avoid: forgetting int()

PYTHONedit me
with open("scores.txt", "w") as f:
    f.write("Sunny,80\n")

with open("scores.txt") as f:
    name, score = f.readline().strip().split(",")

print(score + 5)
OUTPUT
TypeError: can only concatenate str (not "int") to str

score is the text "80", not the number 80. Text from a file is always a string, like text from input().

Good: convert as you load

PYTHONedit me
with open("scores.txt", "w") as f:
    f.write("Sunny,80\n")

with open("scores.txt") as f:
    name, score = f.readline().strip().split(",")

print(name, int(score) + 5)
OUTPUT
Sunny 85

Common beginner doubt: "What if a name has a comma in it?" Then split(",") cuts it in the wrong place. Python has a csv module that handles that, but for simple names and numbers, split(",") is all you need.

Save one record per line with commas; load it with split(",") and turn numbers back with int().

your turnPredict the output

What will this print?

with open("pets.txt", "w") as f: f.write("Rocky,dog,3\n") with open("pets.txt") as f: parts = f.read().strip().split(",") print(parts[1], len(parts))
Your turn! What will this code show on the screen?
your turnPredict the output

Remember the math module?

import math print(math.sqrt(49))
Your turn! What will this code show on the screen?

Practice: with

Solve these to lock in what you learned in this topic. Each one runs in your browser.

  1. 177.Fix the Python Program That Never Closes Its FileEasySolve
  2. 178.Python Program to Read a File Safely with try and exceptMediumSolve
  3. 179.Python Program to Save and Load a Score ListHardSolve