Menu
Coddy logo textTech

Context Managers

Part of the Object Oriented Programming section of Coddy's Python journey — lesson 41 of 64.

Context managers allow you to allocate and release resources precisely when needed. They ensure proper cleanup even if errors occur.

Here is the most common example using the with statement:

with open('example.txt', 'w') as file:
    file.write('Hello, world!')
# File is automatically closed here

The file is automatically closed after the block, even if an exception occurs.

Create your own context manager by implementing __enter__ and __exit__ methods:

class MyContext:
    def __enter__(self):
        print("Entering the context")
        return self
    
    def __exit__(self, exc_type, exc_val, exc_tb):
        print("Exiting the context")
        return False  # Don't suppress exceptions

Use your custom context manager:

with MyContext() as ctx:
    print("Inside the context")

Output:

Entering the context
Inside the context
Exiting the context

Create a more practical context manager for database connections:

class DatabaseConnection:
    def __init__(self, db_name):
        self.db_name = db_name
        self.connection = None
    
    def __enter__(self):
        print(f"Connecting to {self.db_name}")
        self.connection = f"Connection to {self.db_name}"
        return self.connection
    
    def __exit__(self, exc_type, exc_val, exc_tb):
        print(f"Closing connection to {self.db_name}")
        self.connection = None

with DatabaseConnection("users_db") as conn:
    print(f"Using {conn}")
    print("Performing database operations...")

Handle exceptions in context managers:

class SafeContext:
    def __enter__(self):
        print("Setting up resources")
        return self
    
    def __exit__(self, exc_type, exc_val, exc_tb):
        print("Cleaning up resources")
        if exc_type:
            print(f"An exception occurred: {exc_val}")
        return False  # Don't suppress the exception

with SafeContext():
    print("Working with resources")
    # raise ValueError("Something went wrong")  # Uncomment to test

Output:

Connecting to users_db
Using Connection to users_db
Performing database operations...
Closing connection to users_db
Setting up resources
Working with resources
Cleaning up resources

The __exit__ method receives three parameters:

  • exc_type: Exception type (or None)
  • exc_val: Exception value (or None)
  • exc_tb: Exception traceback (or None)

Key Point: Context managers use __enter__ and __exit__ methods to manage resources. The with statement automatically calls these methods, ensuring proper setup and cleanup. This is especially useful for files, database connections, and other resources that need guaranteed cleanup.

challenge icon

Challenge

Easy

In this challenge, you'll implement a context manager class that measures elapsed time between entering and exiting a context block.

  • timer.py - Contains the Timer class implementation (this is the file you'll edit)
  • driver.py - Contains comprehensive test cases (do not modify)

Implement the Timer context manager in timer.py following the TODO comments. The class should:

  1. Record start time when entering a context
  2. Record end time when exiting
  3. Calculate and display the elapsed time

Cheat sheet

Context managers allocate and release resources precisely when needed, ensuring proper cleanup even if errors occur.

Use the with statement for automatic resource management:

with open('example.txt', 'w') as file:
    file.write('Hello, world!')
# File is automatically closed here

Create custom context managers by implementing __enter__ and __exit__ methods:

class MyContext:
    def __enter__(self):
        print("Entering the context")
        return self
    
    def __exit__(self, exc_type, exc_val, exc_tb):
        print("Exiting the context")
        return False  # Don't suppress exceptions

with MyContext() as ctx:
    print("Inside the context")

The __exit__ method receives three parameters:

  • exc_type: Exception type (or None)
  • exc_val: Exception value (or None)
  • exc_tb: Exception traceback (or None)

Handle exceptions in context managers:

class SafeContext:
    def __enter__(self):
        print("Setting up resources")
        return self
    
    def __exit__(self, exc_type, exc_val, exc_tb):
        print("Cleaning up resources")
        if exc_type:
            print(f"An exception occurred: {exc_val}")
        return False  # Don't suppress the exception

Try it yourself

from timer import Timer
import time

# Test case handler
test_case = input()

if test_case == "basic_test":
    # Basic functionality test
    with Timer():
        # Simulate some work
        time.sleep(2)  # This makes the program wait for 2 seconds

elif test_case == "nested_contexts":
    # Test nested context managers
    with Timer():
        time.sleep(1)
        with Timer():
            time.sleep(1)

elif test_case == "exception_handling":
    # Test exception handling within context
    try:
        with Timer():
            time.sleep(1)
            raise ValueError("Test exception")
    except ValueError as e:
        print(f"Caught exception: {e}")

elif test_case == "zero_sleep":
    # Test with minimal sleep
    with Timer():
        time.sleep(0.001)

elif test_case == "multiple_timers":
    # Test multiple timers in sequence
    with Timer():
        time.sleep(1)
    
    with Timer():
        time.sleep(0.5)
    
    with Timer():
        time.sleep(2)

elif test_case == "as_decorator":
    # Test timer in a function context
    def timed_function():
        with Timer():
            time.sleep(2)
    
    timed_function()

else:
    # Default test - basic functionality
    with Timer():
        # Simulate some work
        time.sleep(2)  # This makes the program wait for 2 seconds
quiz iconTest yourself

This lesson includes a short quiz. Start the lesson to answer it and track your progress.

All lessons in Object Oriented Programming