Typorithm · medium

Files, UTF-8 and context-managed lifetimes

pythonscriptingdata-boundariesindependent-practice
Saved on this device
Full lesson · 4 learning steps Open any exercise for focused practice
1

Step 1 of 4 · intro card

Files, UTF-8 and context-managed lifetimes

0%

Concept and contract

Write Unicode deliberately and verify content, bytes and handle closure in a temporary fixture.

A file operation has a path, an opening mode, an encoding and a resource lifetime. The worked function writes one small text note, reads it back and reports its UTF-8 bytes as hexadecimal alongside the decoded text. The lab gives every case a fresh temporary working directory.

A relative filename in this exercise refers only to that disposable fixture. The function assumes its parent directory already exists and reports a missing parent through FileNotFoundError. It does not scan user folders, choose a production path or silently create an arbitrary directory hierarchy.

Mechanism and worked example

The with statement closes each file handle when its block exits, including an exceptional exit.

The with statement closes each file handle when its block exits, including an exceptional exit. Explicit encoding="utf-8" makes the text-to-byte contract portable. The final closed flag is inspected after leaving the reading block rather than inferred from a successful read.

Python 3.15 makes UTF-8 the default text encoding, but explicit encoding still documents intent and keeps these examples compatible with older interpreters and different environments. Newline handling is also explicit so the returned text and bytes can be compared without platform-dependent translation.

Complete worked example

python

from pathlib import Path

def write_note(filename, text):
    path = Path(filename)
    with path.open("w", encoding="utf-8", newline="") as stream:
        stream.write(text)
    with path.open("r", encoding="utf-8", newline="") as stream:
        result = stream.read()
    return {"text": result, "utf8": path.read_bytes().hex(), "closed": stream.closed}
Reasoning
The text, UTF-8 byte contract and closed reading handle are observed separately.

Counterexamples and common mistakes

The counterexample writes using ASCII, which cannot represent the Ukrainian note in the fixture.

The counterexample writes using ASCII, which cannot represent the Ukrainian note in the fixture. A narrow ASCII-only test would miss that domain mismatch. Another common error uses write mode when the task actually promises to preserve previous content, truncating the file before adding the new note.

Do not confuse a closed handle with durable publication or a crash-safe write. This function demonstrates a small local round trip, not an atomic replacement protocol or a backup strategy. Those guarantees need additional filesystem, flush and recovery reasoning beyond merely using with.

Counterexample: a plausible but incorrect implementation

python

from pathlib import Path

def write_note(filename, text):
    path = Path(filename)
    with path.open("w", encoding="ascii", newline="") as stream:
        stream.write(text)
    with path.open("r", encoding="utf-8", newline="") as stream:
        result = stream.read()
    return {"text": result, "utf8": path.read_bytes().hex(), "closed": stream.closed}
Reasoning
ASCII rejects a valid Unicode note that UTF-8 must preserve.

Independent practice: small Python task

Change the write mode to append so existing note content is preserved.

Change the write mode to append so existing note content is preserved. Keep the explicit UTF-8, exact newline handling, readback and closed-handle result. Predict old newline new newline when the fixture already contains old newline and the call appends new newline.

This is one small resource-mode change rather than a new filesystem tool. Check both a pre-existing file and an absent file in an existing parent. The temporary fixture is rebuilt for every case so one exercise run cannot contaminate the next.

Step 1: Keep the managed write and read blocks. Step 2: Use append mode and retain the exact readback result.

Practice starter: solve before reading the solution

python

from pathlib import Path

def write_note(filename, text):
    path = Path(filename)
    # Append Unicode text, then return the same readback evidence.
    raise NotImplementedError
Reasoning
Change the opening mode without dropping encoding or lifecycle checks.
  • Hint 1: Append mode is a rather than w.
  • Hint 2: Do not remove explicit encoding or newline handling.

Solution, tests and trade-offs

The solution opens the target in append mode, then reads the complete resulting file.

The solution opens the target in append mode, then reads the complete resulting file. Acceptance compares the decoded Unicode text, its known UTF-8 byte representation and the closed flag. The missing-parent case still raises rather than being replaced by an invented successful report.

These checks do not establish concurrent-writer safety or that an append is an application transaction across several files. Keep the learning contract precise. The input strings remain unchanged, while the intended filesystem side effect is confined to the case's disposable directory.

Practice solution and acceptance checks

python

from pathlib import Path

def write_note(filename, text):
    path = Path(filename)
    with path.open("a", encoding="utf-8", newline="") as stream:
        stream.write(text)
    with path.open("r", encoding="utf-8", newline="") as stream:
        result = stream.read()
    return {"text": result, "utf8": path.read_bytes().hex(), "closed": stream.closed}
Reasoning
Append preserves existing content; this is not a crash-durability claim.

Interview reasoning and next step

In an interview, explain why encoding, mode and lifetime are independent choices.

In an interview, explain why encoding, mode and lifetime are independent choices. Show a non-ASCII example and say what happens on an exception inside a with block. Avoid claiming that using pathlib alone makes a write atomic, secure or durable under every failure.

The next topic parses structured data and exports CSV through its actual format library. Text that round-trips through UTF-8 can still be malformed JSON or incorrectly quoted CSV, so encoding success is only one boundary in a useful data pipeline.

Optional stretch — after the core task works: Design a separate atomic-replacement experiment in a disposable directory and state which failure modes it actually covers.

Computer practice: https://applydjinn.com/typorithm/python-lab-20261105.zip. Run verify.py with your selected Python interpreter, then complete an exercise and check it with --practice followed by the lesson id. The lab uses only the standard library and disposable local fixtures; it never connects to the production database or company feeds.

Write Unicode deliberately and verify content, bytes and handle closure in a temporary fixture.