Python Academy · Lesson

__enter__ and __exit__ Protocol

Build context managers using the dunder protocol.

Lesson 2 of 413 steps

__enter__ and __exit__ Protocol is a free Python Academy lesson on CoddyKit. This is lesson 2 of 4. You can read the complete lesson below for free — then practise it hands-on in the browser with a built-in code editor and a 24/7 AI tutor. It is part of the Python Academy learning path, and your progress syncs across the web and the CoddyKit app. The Python Academy course includes 4 lessons in total.

The Context Manager Protocol

Any object that defines __enter__ and __exit__ is a context manager and can be used with with.

class Managed:
    def __enter__(self):
        print("entering")
        return self

    def __exit__(self, exc_type, exc_val, exc_tb):
        print("exiting")
        return False

with Managed() as m:
    print("inside")

__enter__ Return Value

__enter__ is called at the start of the with block. Its return value is bound to the variable after as.

class Resource:
    def __enter__(self):
        self.value = 42
        return self  # bound to 'r'

    def __exit__(self, *args):
        self.value = None
        return False

with Resource() as r:
    print(r.value)  # 42

__exit__ Arguments

__exit__(exc_type, exc_val, exc_tb) receives exception info if an error occurred. If no exception, all three are None.

class Safe:
    def __enter__(self):
        return self

    def __exit__(self, exc_type, exc_val, exc_tb):
        if exc_type is ValueError:
            print(f"Suppressed ValueError: {exc_val}")
            return True   # suppress the exception
        return False      # re-raise anything else

with Safe():
    raise ValueError("oops")  # suppressed

Suppressing Exceptions

Return True from __exit__ to suppress the exception. Return False (or nothing) to let it propagate.

class Ignore:
    def __enter__(self): return self
    def __exit__(self, *args): return True  # swallow all exceptions

with Ignore():
    1 / 0

print("continues here")

A Database Connection Example

A classic use case: acquire a connection on enter, commit/rollback and close on exit.

class DBConn:
    def __enter__(self):
        self.conn = connect_db()
        return self.conn

    def __exit__(self, exc_type, exc_val, exc_tb):
        if exc_type:
            self.conn.rollback()
        else:
            self.conn.commit()
        self.conn.close()
        return False

A Timer Context Manager

Measure elapsed time by recording start in __enter__ and computing delta in __exit__.

import time

class Timer:
    def __enter__(self):
        self.start = time.perf_counter()
        return self

    def __exit__(self, *args):
        self.elapsed = time.perf_counter() - self.start
        print(f"Elapsed: {self.elapsed:.3f}s")
        return False

with Timer():
    sum(range(1_000_000))

Nesting Context Managers

Multiple context managers can be combined on a single with line.

with open("in.txt") as src, open("out.txt", "w") as dst:
    dst.write(src.read())

Reusable vs Single-Use Managers

Context managers whose __enter__ allocates a fresh resource each time are reusable. Those that exhaust an internal state (like a lock held only once) may not be.

class Reusable:
    def __enter__(self):
        return []
    def __exit__(self, *a):
        return False

for _ in range(3):
    with Reusable() as lst:
        lst.append(1)
        print(lst)  # [1] each time

__aenter__ and __aexit__ (Async)

For async context managers, define __aenter__ and __aexit__ coroutines and use async with.

class AsyncDB:
    async def __aenter__(self):
        self.conn = await connect()
        return self.conn

    async def __aexit__(self, *args):
        await self.conn.close()

# async with AsyncDB() as conn:
#     ...

Wrapping File Objects

Python file objects already implement the context manager protocol — never call f.close() manually.

with open("data.txt", "r") as f:
    data = f.read()
# file is closed here automatically
print(f.closed)  # True

Implementing a Lock

Thread locks are context managers: __enter__ acquires, __exit__ releases.

import threading

lock = threading.Lock()

def update_shared():
    with lock:
        # critical section
        pass

Quick Check

What should __exit__ return to suppress an exception?

Recap

Implement __enter__ and __exit__ to create context managers. Return the resource from __enter__, handle cleanup and exception suppression in __exit__.

Free to start

Learn Python with an AI tutor — free

Write and run real code in your browser, get instant help from a 24/7 AI tutor, and pick up where you left off on the web or in the app.

Courses
76
Lessons
320

Frequently Asked Questions

Is the “__enter__ and __exit__ Protocol” lesson free?

Yes — the full text of “__enter__ and __exit__ Protocol” is free to read here on the web. To practise it interactively (a built-in code editor and a 24/7 AI tutor) and unlock the rest of the Python Academy course, upgrade to CoddyKit PRO. The Python Academy course includes 4 lessons in total.

What will I learn in “__enter__ and __exit__ Protocol”?

Build context managers using the dunder protocol. You practise Python Academy with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.

Do I need any experience to start Python Academy?

No prior experience is required. Python Academy on CoddyKit is structured for beginners through advanced learners, so you can start here or from the beginning and move at your own pace. This is lesson 2 of 4.

How long does the “__enter__ and __exit__ Protocol” lesson take?

Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.

Can I write and run code in this Python Academy lesson?

Yes. Every Python Academy lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.

All lessons in this course

  1. The with Statement in Depth
  2. __enter__ and __exit__ Protocol
  3. contextlib: @contextmanager
  4. Practical Context Manager Patterns
← Back to Python Academy