Build a Python context manager class for a with-statement that opens and always closes a resource, even when an exception is raised. Tested live.
The problem
Write MyFile(name) so that with MyFile("test.txt") as f: prints:
File opened
File operations performed ← printed by the code inside the with-block
File closed
__enter__printsFile openedand returns the object__exit__printsFile closed— even when the block raises — and must not swallow the exception
Examples
Example 1
Input
captured(session, MyFile)
Expected output
'File opened\nFile operations performed\nFile closed\n'
Example 2
Input
entered_object(MyFile)
Expected output
'MyFile'
+ 1 hidden test on Submit — closes on error, re-raises.
Edge cases to ask about
- Exception inside the block
- Return value of enter
How the tests call your code
These helpers run before your code. The test inputs above call them.
def session(cls): with cls("test.txt") as f: print("File operations performed") def failing_session(cls): try: with cls("test.txt") as f: raise ValueError("boom") except ValueError: print("error propagated") def entered_object(cls): with cls("x.txt") as f: return type(f).__name__
Hints
0/3How an interviewer scores this
0/9Your code runs in real CPython inside your browser — nothing is sent anywhere. The first run downloads the interpreter (about 6 MB, once). Your code is saved on this device as you type.
Complexity Lab
What does this cost as n grows?
Interviewers score the analysis as much as the code. Commit to an answer first — then check it, and read why.
Pick both to reveal the answer.
From brute force to optimal
The progression an interviewer wants to hear, one step at a time.
| Approach | Time | Space | Idea |
|---|---|---|---|
| Class with __enter__/__exit__ | O(1) | O(1) | |
| best@contextlib.contextmanager | O(1) | O(1) | A generator with try/finally around the yield. |
Walkthrough of the optimal approach (try it yourself first)
with calls __enter__ (its return value is bound by as), runs the block, then always calls __exit__(exc_type, exc, tb) — that is the whole point: cleanup that cannot be skipped. If __exit__ returns a truthy value, the exception is suppressed; returning False lets it propagate.
contextlib.contextmanager turns a generator into the same thing: setup, yield, cleanup in finally.
Complexity: O(1) time, O(1) space. Entering and exiting do constant work.
Reveal the reference solution
class MyFile: def __init__(self, name): self.name = name def __enter__(self): print("File opened") return self def __exit__(self, exc_type, exc, tb): print("File closed") return False # do not suppress exceptions
Follow-ups interviewers ask
- Write it with @contextmanager.
- Suppress only FileNotFoundError.
Frequently asked interview questions
Core interview concepts, complexities, and follow-ups scored by hiring teams.
What is the time complexity of Write a Context Manager (__enter__, __exit__) in Python?
The optimal solution runs in O(1) time and O(1) auxiliary space. Entering and exiting do constant work.
What is the brute-force approach, and how do you optimise it?
Class with __enter__/__exit__: O(1) time, O(1) space. @contextlib.contextmanager: O(1) time, O(1) space. A generator with try/finally around the yield.
What follow-up questions do interviewers ask about Write a Context Manager (__enter__, __exit__)?
Write it with @contextmanager. Suppress only FileNotFoundError.
