The with statement exists to abstract away the standard try/finally pattern for resource management (closing files, releasing locks, rolling back transactions).
It relies on two dunder methods:
__enter__(self): Prepares the resource. What it returns is bound to theasvariable (e.g.,with open() as f:binds the file object tof).__exit__(self, exc_type, exc_val, traceback): Tears down the resource. If thewithblock completes successfully, all three arguments areNone. If an exception is raised inside the block, they contain the exception details.- CRITICAL RULE: If
__exit__returnsTrue, the exception is swallowed. If it returnsNone(orFalse), the exception propagates.
- CRITICAL RULE: If
Writing full classes for simple teardown operations is verbose. The @contextmanager decorator allows you to use a generator instead.
@contextmanager
def manage_resource():
print("Setup")
try:
yield resource # Halts here and runs the 'with' block body
finally:
print("Teardown")If an exception occurs inside the with block, it is injected back into the generator right at the yield statement. If you do not have a try/finally block, your generator will crash and the teardown code will never execute.
In Python, else can be attached to for and while loops.
- Meaning: "Execute the
elseblock if and only if the loop completed naturally without hitting abreak." - Use Case: Searching for an item. If you loop through a list and
breakwhen you find it, theelseblock acts as your "Item not found" fallback.
except: Runs if an exception occurred.else: Runs if NO exception occurred inside thetryblock. It is the proper place to put code that should only execute if thetrysucceeded, without wrapping that extra code inside thetryblock itself (which might mask unrelated bugs).finally: Runs no matter what.