The with Statement · Exercises
Core Python

The with Statement Exercises

4 exercises that build on the Python with Statement lesson, from easy to hard. Each one is checked in your browser when you press Check. Stuck? Use the hint before peeking at the solution.

What this lesson covers: The with statement runs setup code before a block and guaranteed cleanup code after it, even when the block fails, by using an object called a context manager. By the end you can use with for files and other resources, explain what enter and exit do, write your own context manager as a class or with @contextmanager, and use suppress, StringIO and redirect_stdout. You will practise: Save and load a name list; Predict the guard; Fix the temporary mode; A rollback context manager.

0 / 4 completed

The with Statement practice exercises

1. Save and load a name list

Write code Easy

Write two functions, both using a with block:

  • save_names(path, names) writes each name on its own line (a later call replaces the old content).
  • load_names(path) returns the names as a list of strings, without the newline characters.

The code then saves and loads the starter list and prints the result.

Your code
def save_names(path, names):
    # write one name per line
    pass

def load_names(path):
    # return a list of names without the newlines
    return []

save_names("team.txt", ["Asha", "Ben", "Chen"])
print(load_names("team.txt"))

2. Predict the guard

Predict the output Medium

Read the class and the two with blocks, then type exactly what the program prints. Think about what __exit__ returns in each case. Then press Check.

Read this code
class Guard:
    def __enter__(self):
        print("enter")
        return self

    def __exit__(self, exc_type, exc_value, traceback):
        print("exit:", exc_type.__name__ if exc_type else "clean")
        return exc_type is KeyError

with Guard():
    print("body one")

with Guard():
    {}["missing"]
    print("body two")

print("after")

3. Fix the temporary mode

Fix the bug Medium

temporary_mode(name) should switch settings["mode"] to name inside a with block and always restore the old mode afterwards. The program should end by printing normal, but it prints debug because an error happens inside the block. Fix the context manager.

Your code
from contextlib import contextmanager

settings = {"mode": "normal"}

@contextmanager
def temporary_mode(name):
    old = settings["mode"]
    settings["mode"] = name
    yield
    settings["mode"] = old

try:
    with temporary_mode("debug"):
        raise ValueError("oops")
except ValueError:
    print("handled")
print(settings["mode"])

4. A rollback context manager

Write code Hard

Complete the class Rollback, a context manager that protects a dictionary.

  • __enter__ remembers a copy of data and returns data itself, so with Rollback(prices) as p: binds p to the dictionary.
  • __exit__: if the block raised an exception, restore the remembered contents inside the same dictionary object (use clear() and update()). If nothing was raised, keep the changes.
  • With the default quiet=False the exception must still propagate. With quiet=True it must be suppressed.
Your code
class Rollback:
    def __init__(self, data, quiet=False):
        self.data = data
        self.quiet = quiet

    def __enter__(self):
        # remember a copy of the data, then return the data itself
        pass

    def __exit__(self, exc_type, exc_value, traceback):
        # on an error: restore the data, then decide whether to suppress the error
        pass

prices = {"tea": 2, "cake": 4}
with Rollback(prices) as p:
    p["tea"] = 3
print(prices)

with Rollback(prices, quiet=True) as p:
    p["cake"] = 99
    raise ValueError("bad price")
print(prices)

Next lessonPython pathlib

More Python with Statement examples · All Python exercises