Concepts / File handling basics

File handling basics

The with statement automates resource acquisition and cleanup, eliminating the need for explicit try...finally blocks.

  • Programming

The Risk of an Unreleased File

Opening a file claims a resource from the operating system. That resource remains claimed until the file is closed. If the program crashes before reaching a close operation, the file can remain open, wasting system resources and potentially preventing other programs from accessing it. File handling therefore has a simple lifecycle: acquire the resource, use it, and release it.

Python provides the with statement to manage this lifecycle automatically. Instead of separately remembering to close a file after every possible path through the program, you place the file operation inside a with block. Python then handles the cleanup when the block ends.

thenexecution continuesalwaysAcquire fileresource obtainedUse filewith block runsLeave blocknormal exit or exceptionClose fileautomatic cleanup
What happens to a file resource from acquisition through use to automatic cleanup when execution leaves the with block?

Tracing the File State

What do you think happens?

A file is opened inside a with block, and an exception occurs while the block is processing the file. What happens to the file?

  • The file remains open because the block ended abnormally.
  • The file is closed automatically before the exception continues.
  • The file is closed only if the program catches the exception.
Reveal answer

Answer: The file is closed automatically before the exception continues.

The with protocol calls __exit__ after the block, including when an exception is raised. The cleanup occurs before the exception reaches an exception handler or causes the program to stop.

resource acquisitionblock ends or exception occursUnopenedno resource claimedOpenresource in useClosedresource released
How does a file change between unopened, open, and closed states as the with statement runs?

Processing a File Safely

A program needs to open a file and iterate through its lines.

Acquire: The with statement performs the file resource acquisition, typically using open for a file.

Bind: The acquired resource is associated with the variable named after as.

Process: The indented block iterates through the file's lines while the file is open.

Release: When execution leaves the block, the file closes automatically. No explicit close call is needed.

The file is used during the block and cleaned up automatically afterward.

The with Protocol

The with statement works through a protocol: a set of rules describing how the statement interacts with the resource object. The protocol calls __enter__ before the with block begins and __exit__ after the block finishes. This is what connects resource acquisition and cleanup to the block's control flow.

__enter__ is the protocol step called before the code inside the with block. __exit__ is the protocol step called after the block, including when an exception is raised inside it.

callsthennormal or exceptional exitcleanupwith statementresource supplied__enter__before blockBlock bodyfile processing__exit__after blockResource releasedcleanup complete
How do __enter__ and __exit__ get called before and after the body of a with statement?

For file handling, this protocol means the file is acquired before processing begins and closed after processing ends. If processing raises an exception, __exit__ still runs before the exception reaches an exception handler or stops the program. The cleanup guarantee is therefore tied to leaving the block, not only to successful completion.

Writing the Resource Pattern

The structure of a file-handling with statement is: write with, then the resource acquisition, typically open for files; write as; provide a variable name; add a colon; and place the file-processing code in the indented block. The block is the region in which the resource is used.

  • with introduces the managed resource statement.
  • The resource acquisition, typically open for files, obtains the file resource.
  • as associates the acquired resource with a variable name.
  • The colon begins the block whose resource use is managed.
  • The indented block contains the file-processing operations.
  • Leaving the block triggers automatic cleanup.

with Compared with try...finally

Manual resource management uses a try...finally pattern so that cleanup code runs whether the protected operations finish normally or raise an exception. For a file, that approach requires the programmer to arrange an explicit close operation in the finally part.

The with statement provides the same important cleanup guarantee without requiring the repeated manual pattern. It encodes the acquisition and cleanup behavior into the language construct, making the result shorter, clearer, and less error-prone. A programmer cannot accidentally omit the finally block or its close operation when using the managed pattern.

normal control flowerror control flownormal control flowerror control flowwith statementcleanup encodedtry...finallycleanup writtenBlock endsautomatic cleanuptry endsfinally runsException raised__exit__ still runsException raisedfinally still runs
How does control flow differ between a with statement and an explicit try...finally block when normal execution or an error occurs?
with statementManual try...finally
Acquisition and cleanup are expressed through one language construct.The programmer writes the cleanup structure explicitly.
The resource is cleaned up when the block ends or an exception occurs.The finally part is used to guarantee cleanup after normal or exceptional control flow.
Shorter, clearer, and less error-prone for this recurring pattern.More verbose and easier to get wrong if cleanup code is omitted.

Mistakes Beginners Make

  • Assuming cleanup happens only after successful processing.

    The with protocol calls __exit__ even when an exception is raised.

    Fix: Treat the with block as safe for both normal completion and exceptional completion.

  • Replacing the managed pattern with a manually remembered close operation.

    Control may leave the intended path before the close operation is reached, leaving the resource open.

    Fix: Use a with statement so cleanup is connected to leaving the block.

  • Putting file processing outside the with block.

    The with statement closes the file when the block ends, so later operations are outside the resource's managed use period.

    Fix: Place the operations that use the file inside the indented with block.

Practice the Lifecycle

MEDIUM

Describe the order of events for a with statement that opens a file, processes two lines, and then encounters a ValueError while still inside the block. Name the protocol steps and state when the file is closed.

Hints
  • Identify the protocol method called before the block.
  • The exception occurs during the block, not before resource acquisition.
  • Identify what runs after the block when an exception occurs.

Checking Your Trace

Trace the managed file lifecycle through normal entry, file processing, an exception, and cleanup.

Entry: __enter__ is called before the file-processing block.

Processing: The block processes the file's lines.

Exception: A ValueError occurs during processing, so normal completion of the block does not continue.

Cleanup: __exit__ runs before the exception reaches an exception handler or stops the program, and the file closes.

An exception changes how execution leaves the block, but it does not remove the with statement's cleanup step.

Key Takeaways

  1. Opening a file claims an operating-system resource that must be released.
  2. The with statement combines resource acquisition, use, and automatic cleanup.
  3. __enter__ runs before the with block, while __exit__ runs after it.
  4. A file opened with with is closed when the block ends, including when an exception occurs.
  5. For recurring resource-management tasks, with is shorter, clearer, and less error-prone than manual try...finally code.

Key Takeaways

  • The with statement manages the lifecycle of a file resource.
  • __enter__ is called before the block and __exit__ is called after it.
  • Cleanup occurs when the block ends normally or when an exception leaves it.
  • The with pattern avoids the repeated boilerplate and risks of manual try...finally resource management.