Data AnalyticsPython foundations for analysts

Use context managers to close files reliably

PK
Pankit Kumar
Sr. Data Scientist at Parexel (a Goldman Sachs–backed company) · 20 September 2026 · 3 min read
Technically reviewed by Ishaan Sharma
In this article (6 sections)

Use a with statement to give an open file a clear lifetime. The file is closed when control leaves the block, including when an exception propagates. That makes resource cleanup predictable and keeps ownership visible to the reader.

Closing a file does not mean the written dataset is complete, valid or atomically published. Those are separate guarantees that require their own design.

Observe closure on both paths

Run this self-contained example from the Python reporting lab. It uses a temporary file and deliberately raises an exception after reading it.

python
from pathlib import Path
from tempfile import TemporaryDirectory

with TemporaryDirectory() as directory:
    source = Path(directory) / "sample.txt"
    source.write_text("order_id,amount\nR1,19.00\n", encoding="utf-8")
    with source.open(encoding="utf-8") as normal:
        assert not normal.closed
        assert normal.readline().strip() == "order_id,amount"
    assert normal.closed
    try:
        with source.open(encoding="utf-8") as exceptional:
            assert exceptional.read().startswith("order_id")
            raise ValueError("deliberate_validation_failure")
    except ValueError as error:
        assert str(error) == "deliberate_validation_failure"
    assert exceptional.closed
    print("File closed after normal and exceptional exits")

The with-statement reference describes how context managers enter and exit their managed scope. File objects implement that protocol; the assertions make the cleanup observable.

Put processing inside the resource lifetime

csv.DictReader reads from its underlying handle as it is iterated. Creating the reader inside a with block and trying to consume it after the block closes the file is a lifetime error.

Either finish iteration inside the block or deliberately materialize the required records before leaving it. Materialization consumes memory, so do not convert a large file to a list solely to avoid thinking about resource ownership.

The lab's loader receives an open handle and consumes it during the call. The caller owns opening and closing that handle. This separation also makes it easy to test the loader with an in-memory text stream.

Do not assume cleanup reverses a partial write

If a program opens a destination with mode w, the prior contents may be truncated before later validation fails. A with statement will close the file, but it will not restore those prior bytes.

Validate inputs and calculate outputs before opening the final destination when practical. For a production single-file handoff, a common design writes a temporary file in the target filesystem and replaces the final path only after successful completion, subject to the filesystem's guarantees.

Multiple related files need additional coordination. The lab writes accepted rows, rejected rows and a summary as separate files; it explicitly does not claim an atomic three-file transaction. A failure between writes can leave an incomplete output directory.

Keep exception behavior visible

A context manager can be designed to suppress an exception, but ordinary file cleanup should not be mistaken for error handling. The example catches its deliberate ValueError outside the with block so the failure remains explicit.

Avoid adding a broad except around writing merely to print done afterward. A report that could not be written should fail visibly, even if its input file was correctly closed.

Test the failure you care about

Resource tests should inspect observable behavior. Here, closed confirms cleanup. A report-write test should additionally inspect output existence, content and failure status. Those assertions answer different questions.

On some platforms, an unclosed file can interfere with rename or deletion; on others, the same operation may appear to work. Relying on one platform's permissive behavior can hide a lifecycle bug. Explicit ownership is clearer across environments.

Exercise: create a CSV reader inside a with block and deliberately consume it after closure. Observe the failure, then move iteration into the block. Explain when returning a list is acceptable and when a streaming interface is preferable.

NeuraPath's Data Analytics with Generative AI course connects Python resource handling with dependable reporting. Correct cleanup is one part of reliability; output integrity still needs its own checks.

Continue learning

This article is part of the Python foundations for analysts sequence. Use the neighbouring tasks when you need the prerequisite or the next application.

PK
Pankit Kumar
Lead Instructor, NeuraPath Academy

Pankit Kumar has 10 years in Data Science & AI, building and shipping production systems in regulated pharma and clinical environments. He is a freelance trainer at Boston Institute of Analytics, AnalytixLabs and Scaler, and has taught this material to thousands of working professionals.

This article is part of our Data Analytics with Generative AI programme — 3–4 months. The full analyst stack — Excel, SQL, Power BI and Python pipelines — then a generative-AI layer you can prove is right.

Explore Data Analytics with Generative AI
Counselling is free · no obligation

Not sure which programme fits?

Tell us your background and we will map it to the right entry point — including saying so when a cheaper programme is the better fit. A counsellor replies within one working day.