Skip to content

Archive

Python

119 articles
Python 08 Sep 2026 8 min read

Use Native Max-Heaps with Python heapq

Python’s heapq module has historically been centered on min-heaps: the smallest element lives at index zero. Developers who needed a max-heap commonly negated numeric priorities before pushing them and negated them again after popping. Python 3.14 makes that workaround unnecessary for many programs. heapq now exposes a complete max-heap API: heapify_max(), heappush_max(), heappop_max(), heappushpop_max(), and heapreplace_max(). The new functions are simple, but using them well still requires understanding heap invariants, fixed-size selection, tie-breaking, and the important difference between push-pop and replace operations.

Python 08 Sep 2026 11 min read

Run CPU-Bound Python Work with InterpreterPoolExecutor

Python has traditionally offered two familiar high-level choices for parallel work: threads and processes. Python 3.14 adds a third option to concurrent.futures: InterpreterPoolExecutor. It runs workers in separate Python interpreters inside one process. Each worker has its own interpreter state and its own Global Interpreter Lock (GIL), so pure Python code can execute on multiple CPU cores at the same time. That makes the executor interesting for CPU-bound workloads, but it is not a drop-in way to make arbitrary threaded code parallel. Interpreter isolation changes the programming model. Mutable Python objects are not simply shared between workers, submitted work crosses a serialization boundary, imports and module globals are interpreter-local, and extension compatibility deserves deliberate testing.

Python 08 Sep 2026 12 min read

Process Template Strings Safely with Python T-Strings

Python’s f-strings are excellent when the desired result is immediately a string. That same immediacy becomes a limitation when an application needs to inspect interpolated values before deciding how they should be represented. Python 3.14 adds template string literals, usually called t-strings, for that boundary. A t-string looks much like an f-string, but it does not immediately collapse its literal text and interpolated values into one str. Instead, it produces a structured Template object from string.templatelib.

Python 08 Sep 2026 8 min read

Parse TOML Configuration Safely with Python tomllib

Python 3.11 added tomllib, giving applications a standard-library parser for TOML configuration files. That removes a dependency for a common task, but parsing is only one part of loading configuration correctly. A configuration loader still needs to decide how large an input may be, what keys and types are accepted, whether floating-point values require exact decimal semantics, and how syntax errors should be reported. It also needs to remember that tomllib reads TOML; it is not a TOML writer or a schema validator.

Python 08 Sep 2026 6 min read

Keep Request State Local with Python contextvars

Passing a request ID through every function is explicit, but after a few layers it can become noise. Logging is the example I keep running into: the logger needs the request ID, while most business functions do not actually care about it. A global variable looks tempting until two requests run concurrently. threading.local() fixes a different problem, but one event-loop thread can execute many asyncio tasks. Python’s contextvars module is designed for this kind of context-local state.

Python 08 Sep 2026 8 min read

Inspect ZIP Archives Before Extraction in Python

ZIP extraction looks like a single filesystem operation, but an archive is really a collection of filenames, metadata, and compressed byte streams supplied by whoever created the file. When the archive is untrusted, that metadata belongs at a trust boundary. Python’s zipfile module provides convenient extraction helpers, and those helpers include protections for suspicious path components. The documentation still warns against extracting untrusted archives without prior inspection. That distinction is useful: library normalization is not the same thing as an application-specific acceptance policy.

Python 08 Sep 2026 8 min read

Handle Time Zones Correctly with Python zoneinfo

Time-zone code becomes difficult when an application needs more than a fixed UTC offset. Civil-time rules change, daylight-saving transitions can repeat or skip local clock readings, and the rules for a place are not captured by labels such as UTC+7 or UTC-5. Python 3.9 added zoneinfo to the standard library to provide IANA time-zone support through the familiar datetime API. It is the right starting point when an application needs rules for named zones such as Asia/Jakarta, Europe/Berlin, or America/New_York.

Python 08 Sep 2026 7 min read

Generate Time-Ordered IDs with Python UUIDv7

Random UUIDs are convenient identifiers: they can be generated without coordinating with a database, and the probability of collision is tiny. But a UUIDv4 primary key has one awkward property for ordered indexes: newly generated values are spread across the key space instead of tending toward the end of the index. UUID version 7 keeps the decentralized 128-bit UUID shape while putting a Unix-epoch millisecond timestamp at the front. Python 3.14 adds uuid.uuid7() to the standard library, so applications no longer need a third-party package just to generate RFC 9562 UUIDv7 values.

Python 08 Sep 2026 8 min read

Copy File-Like Streams Safely with shutil.copyfileobj in Python

Many Python programs need to move bytes between objects that behave like files without caring whether either side is an ordinary disk file. The source might be a decompressor, an uploaded file, an in-memory buffer, or a response body. The destination might be a temporary file, another buffer, or a wrapper that transforms data as it is written. For that job, shutil.copyfileobj() is a small but useful standard-library primitive. It copies from one file-like object to another and lets the objects themselves define where the bytes ultimately come from and go.

Python 08 Sep 2026 8 min read

Copy and Move Paths with pathlib in Python 3.14

Python 3.14 adds high-level copy and move operations directly to pathlib.Path. Path.copy(), Path.copy_into(), Path.move(), and Path.move_into() make many filesystem workflows easier to express without switching between pathlib, shutil, and os for basic operations. The convenience is useful, but filesystem mutations still need explicit policy. Overwrites, symbolic links, metadata, cross-filesystem moves, partial failure, and concurrent changes can all affect correctness. The four new operations Use copy() when the destination path itself is known:

Python 08 Sep 2026 8 min read

Compare Neighboring Values Lazily with itertools.pairwise

Many data-processing tasks are really questions about transitions: Did a measurement increase? How long was the gap between two events? Did a state change? Is a sequence sorted? These problems need neighboring values, not arbitrary pairs. Python 3.10 added itertools.pairwise() for exactly this pattern. It produces overlapping adjacent pairs lazily, which makes the intent clearer than manual indexing and lets the same code work with lists, generators, files, and other iterables.

Python 08 Sep 2026 5 min read

Change Working Directories Safely with contextlib.chdir

Changing the current working directory is one of those operations that looks local in code but is global in effect. I still see scripts that call os.chdir(), do some work, and then try to remember where they started. Python 3.11 added contextlib.chdir(), which makes the restore step much cleaner. To be fair, though, a context manager does not make changing the working directory concurrency-safe. The important part is understanding what state is being changed and how long that state stays changed.

Python 08 Sep 2026 7 min read

Budget Async Work with asyncio.timeout

Timeouts in asynchronous programs are easy to scatter and surprisingly hard to compose. A service call gets five seconds, a database query gets five more, and a retry gets another five. Each individual limit looks reasonable, yet the whole request can run far beyond the caller’s budget. Python 3.11 added asyncio.timeout(), an asynchronous context manager that makes a different model practical: put a time budget around a block of work, not just around one awaitable.

Python 08 Sep 2026 9 min read

Batch Python Iterables Lazily with itertools.batched

Processing data in groups is common in Python. An application may send records to an API 100 at a time, insert rows into a database in manageable groups, or divide a stream of identifiers into work units without first loading the whole input into memory. Since Python 3.12, the standard library provides itertools.batched() for this pattern. It consumes an iterable lazily and yields tuples containing up to a requested number of items. Python 3.13 added a strict option for cases where an incomplete final batch should be treated as an error.

Python 07 Sep 2026 11 min read

Use Memory-Mapped Files for Random Access in Python

Reading a file with read() gives your program a straightforward model: ask for bytes, receive a bytes object, and let Python manage the buffer. That is often the right choice. Some workloads are different. A program may need to inspect small regions scattered across a large file, search the same file repeatedly, or pass file-backed bytes to APIs that understand the buffer protocol. Repeated seek() and read() calls can work, but they make every access an explicit file operation in your code.

Python 07 Sep 2026 11 min read

Manage Dynamic Resource Lifetimes in Python with ExitStack

A normal with statement works best when you know the resources before the block starts: with open("input.csv", "rb") as source, open("output.csv", "wb") as target: ... The structure is clear because both files are known in advance. Python enters each context manager and guarantees that their exit logic runs when the block finishes, including when an exception leaves the block.

Python 07 Sep 2026 11 min read

Create and Clean Up Temporary Files Safely in Python

Temporary files appear in more programs than their name suggests. A command-line tool may need scratch space while transforming a large file. A test may need an isolated directory. A program may need to hand a real filesystem path to another process and remove it afterward. The risky part is not writing the bytes. It is choosing a name, creating the file without a race, deciding who owns cleanup, and handling differences between a file object and a filesystem path.

Python 07 Sep 2026 8 min read

Build Reliable Worker Queues in Python with queue.Queue

A worker thread is easy to start. A reliable worker queue is harder. The difficult parts appear when production code must answer questions such as: What happens when producers are faster than consumers? How does the main thread know that processing, rather than merely dequeuing, is complete? How do workers stop without abandoning queued work? What happens if processing raises an exception? Python’s queue.Queue provides the synchronization needed to pass work safely between threads, but correct coordination still depends on a few application-level invariants. The most important are to bound work when memory matters, pair every successful get() with exactly one task_done(), and separate “all work is finished” from “workers should exit.”

Python 07 Sep 2026 11 min read

Bound In-Flight Thread Pool Work in Python

A thread pool limits how many functions run at the same time, but it does not automatically limit how much work your producer can queue. That distinction matters when the input is large or unbounded. A loop can submit millions of tasks to a ThreadPoolExecutor while only a handful of worker threads execute them. The remaining tasks are pending Future objects, along with their arguments and other referenced state. If the producer is much faster than the workers, memory use can grow long before CPU or network capacity is exhausted.

Python 05 Sep 2026 12 min read

Parse Binary Records Safely in Python with struct

Binary files and network messages often begin with fixed-width fields: a four-byte signature, a one-byte version, a two-byte payload length, or a four-byte identifier. Those fields are easy to describe on paper but surprisingly easy to parse incorrectly in code. The difficult part is not converting bytes to integers. It is preserving the binary layout contract: exactly which byte belongs to which field, which byte order is used, how wide each value is, and what should happen when the input is incomplete or malformed.

Python 05 Sep 2026 9 min read

Build Reliable Priority Queues in Python with heapq

A priority queue answers one question repeatedly: which pending item should run next? Schedulers, retry systems, graph algorithms, simulations, and background workers all need some version of that operation. A list can hold pending items, but finding the best one by scanning costs linear time each time. Keeping the whole list sorted makes retrieval cheap, but insertion has to preserve that full ordering. Python’s heapq module uses a heap instead. A heap is partially ordered: it guarantees that the smallest item is at heap[0], but it does not keep every element globally sorted. Push and pop operations take logarithmic time, while reading the current minimum is constant time.

Python 05 Sep 2026 9 min read

Buffer Temporary Data in Python with SpooledTemporaryFile

Temporary data often has an awkward size profile. Most requests may produce a few kilobytes, while an occasional import, report, archive, or upload grows to hundreds of megabytes. Using io.BytesIO is convenient for the small case, but its contents stay in memory. Using a temporary file avoids keeping the whole payload in memory, but every payload uses file-system-backed storage even when it is tiny. Python’s tempfile.SpooledTemporaryFile gives you a middle ground. It behaves like a file object while keeping data in memory up to a configured threshold. When the data grows beyond that threshold, it rolls over to a temporary file and continues through the same interface.

Python 04 Sep 2026 8 min read

Use Slotted Dataclasses When Object Shape Is Fixed in Python

Python dataclasses reduce boilerplate for record-like classes, but their instances are still ordinary Python objects by default. Declared fields normally live in an instance dictionary, and new attributes can be attached later. That flexibility is useful until the model is supposed to have a fixed shape. Coordinates, parsed records, configuration snapshots, protocol messages, and other compact value objects often have a known set of fields. When many such objects exist, keeping dynamic per-instance attribute storage may also be unnecessary.

Python 04 Sep 2026 9 min read

Use functools.singledispatch for Type-Based Extension Points in Python

A function often starts with one input type and later grows branches for several related types. The first version may be straightforward: def render(value): if isinstance(value, str): ... elif isinstance(value, list): ... elif isinstance(value, dict): ... As the number of supported types grows, this function becomes the place where every extension must be added. The branches mix dispatch logic with the behavior for each type, and independently maintained modules cannot add support without editing the central function.