Explore programming tutorials, exercises, quizzes, and solutions!
Python Context Managers Exercises
1/15
In Python, context managers are used to manage resources like files, network connections, and database sessions. They ensure that resources are properly acquired and released, avoiding issues such as memory leaks or file locks.
The most common way to use a context manager is with the with statement. When using with, Python automatically handles the setup and teardown of the resource. Behind the scenes, a context manager is any object that implements the __enter__() and __exit__() methods.
Consider the following Python code:
with open("sample.txt", "r") as file:
content = file.read()
print(content)
What does this code demonstrate about context managers?
This code demonstrates Python’s built-in context manager in action via the with statement:
open("sample.txt", "r") opens the file in read mode.
The with statement ensures that once the block finishes (even if an error occurs), the file is automatically closed, preventing resource leaks.
file.read() reads the full contents of the file into the variable content.
Using context managers makes your code more concise, reliable, and Pythonic. You don't need to explicitly call file.close(), which reduces the chance of forgetting to release resources — a common issue in large programs or when exceptions are raised.
You can also define custom context managers using classes with __enter__() and __exit__() or using the @contextmanager decorator from the contextlib module.
Which special method must a class implement to be used as a context manager with a with statement?
To function as a context manager, a class must define the __enter__ and __exit__ methods. __enter__ is called at the start of the with block, and __exit__ is called when the block is exited, either normally or due to an exception. This allows setup and teardown logic to be managed cleanly and predictably.
What will be printed by the following code?
with open('test.txt', 'w') as f:
print(f.closed)
print(f.closed)
Assume test.txt exists and is writable.
Inside the with block, the file f is open, so f.closed returns False. Once the block ends, Python automatically closes the file, so f.closed then returns True. This is a key benefit of using context managers—they handle resource cleanup automatically.
Which of the following is true about using context managers in Python?
Context managers are used to ensure that resources are properly acquired and released. Although commonly used with files, they can manage any resource such as database connections, network sockets, or locks. They don’t suppress exceptions unless explicitly programmed to do so in the __exit__ method.
What will the following custom context manager print?
class Demo:
def __enter__(self):
print("Entering")
return self
def __exit__(self, exc_type, exc_val, exc_tb):
print("Exiting")
with Demo() as d:
print("Inside block")
When the with block starts, the __enter__ method is executed first, printing "Entering". Then the code inside the block runs, printing "Inside block". After that, __exit__ is called automatically when the block finishes, printing "Exiting". This is the standard flow of a context manager.
Which of the following code snippets correctly implements a context manager that suppresses ZeroDivisionError?
To suppress an exception in a context manager, the __exit__ method must return True when that exception type occurs. Option 1 correctly checks if exc_type is ZeroDivisionError and returns True in that case, preventing the exception from propagating. The others either always return False or compare the wrong object.
What will be the output of the following code?
class MyManager:
def __enter__(self):
print("Start")
return "Resource"
def __exit__(self, exc_type, exc_val, exc_tb):
print("End")
with MyManager() as val:
print(val)
When the with statement is executed, __enter__ runs and prints "Start", returning "Resource" which is assigned to val. The block then prints "Resource". After the block finishes, __exit__ is automatically called, printing "End". So the full output is: Start → Resource → End.
Which of the following use cases is most appropriate for implementing a custom context manager?
Context managers are ideal for scenarios that require setup and teardown actions, such as managing database connections. A context manager can ensure that transactions are committed if successful or rolled back in case of an error, reducing the chance of leaving the database in an inconsistent state. The other options don't involve resource management and are better handled with regular logic.
What will be the output of the following code?
class CM:
def __enter__(self):
print("Entered")
return 10
def __exit__(self, exc_type, exc_val, exc_tb):
print("Exited")
with CM() as x:
x += 5
print(x)
The __enter__ method returns 10, which is assigned to x. Inside the with block, x is incremented to 15 and printed. Once the block is done, __exit__ is called, printing "Exited". This confirms that context manager values can be manipulated inside the block like regular variables.
You want to measure the execution time of a block of code using a custom context manager. Which implementation is correct?
Option 4 correctly implements a context manager that measures elapsed time. __enter__ records the start time and returns the instance so that it can be used inside the with block if needed. __exit__ then calculates and prints the duration. Option 1 lacks a return statement in __enter__, and option 2 isn’t a context manager at all.
What happens if a context manager's __exit__ method returns False when an exception occurs in the with block?
When an exception is raised inside a with block, Python calls the __exit__ method. If __exit__ returns False, the exception is not suppressed and will propagate as usual (i.e., it will be re-raised after the __exit__ call). Only returning True suppresses the exception. This behavior allows custom logic while still respecting exception flow.
Consider the following code. What will be printed?
class Manager:
def __enter__(self):
print("Enter")
return self
def __exit__(self, exc_type, exc_val, exc_tb):
print("Exit")
return True
with Manager():
raise ValueError("Oops")
print("Done")
The context manager's __exit__ method is designed to return True when an exception occurs, which means the exception is suppressed. "Enter" is printed when __enter__ runs, "Exit" when __exit__ runs, and since the exception is suppressed, execution continues and "Done" is printed afterward.
What will be the final output of the following code?
class Tracker:
def __enter__(self):
print("Opening")
return self
def __exit__(self, exc_type, exc_val, exc_tb):
print("Closing")
return exc_type is None
def risky_operation(self):
raise RuntimeError("Failure")
try:
with Tracker() as t:
t.risky_operation()
except RuntimeError:
print("Handled")
The __enter__ method prints "Opening", and then risky_operation raises a RuntimeError. The __exit__ method is still called and prints "Closing". Since __exit__ returns False (because exc_type is not None), the exception is not suppressed and propagates to the outer try-except, where it is caught and "Handled" is printed. This demonstrates how context managers interact with exception handling.
What will be printed when the following code is executed?
class CM:
def __enter__(self):
print("Start")
return None
def __exit__(self, exc_type, exc_val, exc_tb):
print("End")
if exc_type:
print(f"Exception: {exc_type.__name__}")
return True
with CM():
print(1 / 0)
print("After block")
The code enters the context, prints "Start", and then raises a ZeroDivisionError. The __exit__ method is called next, prints "End", and detects the exception type, printing "Exception: ZeroDivisionError". Since it returns True, the exception is suppressed, allowing the program to continue and print "After block".
What will the following code output?
class Nested:
def __init__(self, label):
self.label = label
def __enter__(self):
print(f"{self.label} enter")
return self
def __exit__(self, exc_type, exc_val, exc_tb):
print(f"{self.label} exit")
with Nested("Outer") as out:
with Nested("Inner") as inn:
print("Inside block")
Context managers follow a stack-like behavior. First, Outer enter is printed, then Inner enter. After the with block, the Inner context manager exits first, printing Inner exit, followed by Outer exit. This nesting order ensures predictable resource management and cleanup in reverse order of entry.
Practicing Python Context Managers? Don’t forget to test yourself later in
our
Python Quiz.
About This Exercise: Python – Context Managers
Welcome to the Python Context Managers exercises — a comprehensive set of challenges designed to help you master one of Python’s most elegant tools for managing resources safely and efficiently. Context managers simplify the handling of setup and cleanup actions around code blocks, ensuring resources like files, network connections, or locks are properly acquired and released. Whether you’re new to Python or looking to deepen your understanding, these exercises will guide you through the core concepts and practical applications of context managers.
In this section, you will learn how to use the with statement to manage resources cleanly and avoid common pitfalls such as resource leaks and inconsistent states. You’ll explore built-in context managers like file handling and threading locks, as well as how to create your own custom context managers using the __enter__ and __exit__ methods or the contextlib module.
These exercises will take you through practical scenarios where context managers improve code readability, safety, and reliability — from safely opening and closing files to managing database transactions and handling exceptions gracefully. You’ll practice writing your own context managers to encapsulate resource management logic and ensure robust program behavior.
Mastering context managers is essential for professional Python developers who want to write clean, maintainable code that handles resources predictably. They are widely used in production-grade applications, frameworks, and libraries, making this skill crucial for both academic and professional growth.
Alongside coding exercises, this section emphasizes best practices such as keeping context manager logic simple, handling exceptions carefully within __exit__, and leveraging the contextlib utilities for elegant solutions. Understanding these principles will help you write safer and more Pythonic code.
We recommend complementing your practice with related topics like decorators, exception handling, and generator functions to build a comprehensive understanding of Python’s advanced features. Quizzes and multiple-choice questions on context managers are also available to reinforce your learning.
Start practicing the Python Context Managers exercises today to write cleaner, safer, and more efficient Python programs. With consistent effort, you’ll become proficient in managing resources elegantly and effectively.