Python
with statement
context managers
Python coding
resource management

What is the Python with statement designed for?

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

Introduction

The Python with statement is designed for context management. Its main job is to guarantee setup and cleanup around a block of code, especially when resources such as files, locks, or database connections must be released even if an exception occurs. It is not just syntactic sugar for prettier code. It encodes a very specific resource-lifetime pattern.

The Core Problem It Solves

Without with, resource management is easy to get wrong. For example, opening a file manually often requires try and finally to guarantee cleanup:

python
1file = open("example.txt", "w")
2try:
3    file.write("hello\n")
4finally:
5    file.close()

This works, but it is repetitive. The with statement packages the same idea more cleanly:

python
with open("example.txt", "w") as file:
    file.write("hello\n")

When the block exits, Python closes the file automatically, even if an exception is raised inside the block.

It Works Through Context Managers

The object used in a with statement must be a context manager. That means it implements two special methods:

  • '__enter__ for setup'
  • '__exit__ for cleanup'

A minimal custom context manager looks like this:

python
1class DemoContext:
2    def __enter__(self):
3        print("enter")
4        return "resource"
5
6    def __exit__(self, exc_type, exc_value, traceback):
7        print("exit")
8        return False
9
10with DemoContext() as resource:
11    print(resource)

__enter__ runs before the body. __exit__ runs afterward, whether the body completed normally or raised an exception.

Cleanup Happens Even on Failure

This is one of the most important design points. The with statement is meant for cases where cleanup must happen regardless of success or failure.

python
with open("example.txt", "r") as file:
    data = file.read()
    raise RuntimeError("something went wrong")

Even though the exception interrupts the block, the file still gets closed. That reliability is the real reason with exists.

Common Real Uses

The with statement appears anywhere setup and teardown belong together. Common examples include:

  • opening files
  • acquiring locks
  • opening database transactions
  • temporarily redirecting output
  • managing temporary directories

A lock example shows the intent clearly:

python
1import threading
2
3lock = threading.Lock()
4
5with lock:
6    print("critical section")

This is much safer than acquiring the lock and hoping every control path releases it correctly.

with Is Not Limited to Built-In Types

You can create your own context managers whenever an object has a meaningful enter-exit lifecycle. You can also write them with contextlib.contextmanager:

python
1from contextlib import contextmanager
2
3@contextmanager
4def temporary_message():
5    print("setup")
6    try:
7        yield "resource"
8    finally:
9        print("cleanup")
10
11with temporary_message() as value:
12    print(value)

This is often the most convenient way to define simple context managers in application code.

Common Pitfalls

The biggest mistake is thinking with is only for files. Files are just the most familiar example. The statement is really about any resource or state that needs guaranteed cleanup.

Another issue is misunderstanding __exit__. Returning True from __exit__ suppresses the exception, which is powerful but easy to misuse. Most context managers should return False or None so exceptions still propagate normally.

People also sometimes use with around objects that are not actual context managers. If the object does not implement the required protocol, the statement will fail.

Finally, do not confuse variable scope with resource scope. The name bound by as can still exist after the block, but the underlying resource may already be closed or cleaned up.

Summary

  • The with statement is designed for context management and guaranteed cleanup.
  • It replaces repetitive try and finally patterns for resource handling.
  • It works with objects that implement __enter__ and __exit__.
  • Its main benefit is reliable cleanup even when exceptions occur.
  • Use it anywhere setup and teardown belong together, not just for file I/O.

Related reading
Free course
Beginner
7 lessons
2 hours
Tackling System Design Interview Problems

A short course that equips you with the skills to approach system design interviews methodically.

Start the free course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

All Rights Reserved.