asyncio vs Threading vs Multiprocessing: Picking the Right Concurrency Model

Every Python developer eventually hits a wall where their code needs to do more than one thing “at once,” and then discovers that Python offers not one but three completely different answers: threading, multiprocessing, and asyncio. They all live in the standard library, they all let you write code that overlaps in time, and their APIs even look superficially similar. But they solve different problems, and picking the wrong one doesn’t just underperform, it can silently fail to help at all. ...

August 31, 2026 · 9 min

Mutable Default Arguments: Python's Favorite Gotcha

Every Python developer eventually writes a function like this, watches it misbehave in a way that makes no sense, and joins the club: def add_item(item, basket=[]): basket.append(item) return basket print(add_item("apple")) # ['apple'] print(add_item("banana")) # ['apple', 'banana'] <- wait, what? You expected ['banana']. Instead the second call remembers the first one. Nothing about the code looks wrong at a glance, which is exactly why this bites so many people, including plenty who’ve been writing Python for years. I’ve shipped this bug myself, in a function that collected validation errors, and didn’t notice until a support ticket showed one request’s errors leaking into an unrelated request. ...

August 27, 2026 · 5 min

Python Logging Done Right

I have never once, in production, wished I had more print() statements to grep through. What I have wished for, repeatedly, at 2am, is a log line that included a request ID, a timestamp in a sane timezone, and a severity level I could filter on. The standard library’s logging module gives you all of that for free. Most people just don’t use it that way, they call logging.info("here") a few times, never touch the configuration, and end up with something barely better than print. This article is about the difference between using logging and using it well. ...

August 25, 2026 · 10 min

Generators and Iterators: Lazy Evaluation in Python

I still remember the first time a generator saved a script from getting OOM-killed. I was processing a multi-gigabyte log file, and the “obvious” version of the code read every line into a list before filtering it. It worked fine on my laptop with a 10MB sample file and then fell over the moment it hit the real dataset in production. Swapping a list comprehension for a generator expression fixed it in about thirty seconds. That asymmetry, huge payoff for a tiny syntax change, is why generators are one of the first things I reach for when data gets big or infinite. ...

August 24, 2026 · 8 min

Building a CLI Tool in Python: Publishing to PyPI

In part 1 we built taskcli’s command structure with Typer. In part 2 we added persistent storage and a pyproject.toml that makes pip install -e . work locally. The last step is making taskcli installable by anyone, anywhere, with a plain pip install taskcli. That means publishing to PyPI, the Python Package Index. What “publishing” actually means PyPI hosts two kinds of build artifacts for every release: A wheel (.whl), a prebuilt, ready-to-install package. pip prefers this when one is available for the user’s platform. A source distribution or sdist (.tar.gz), the raw source plus enough metadata to build a wheel from scratch. pip falls back to this if no matching wheel exists. For a pure-Python tool like taskcli (no compiled extensions), a single wheel works on every platform. Publishing is: build both artifacts, then upload them. ...

August 19, 2026 · 7 min

Building a CLI Tool in Python: Config Files & Packaging

In part 1 we built taskcli, a command-line task tracker, using Typer for argument parsing and subcommands. It works, but every task vanishes the moment the process exits, and there’s no way to install taskcli as a real command on your system. This part fixes both: we’ll persist tasks to a proper data file and package the project with pyproject.toml. Where should data live? The instinct is to write a tasks.json file next to the script. That breaks the moment someone runs taskcli from a different directory, since relative paths resolve against the current working directory, not the tool’s location. ...

August 5, 2026 · 6 min

Building a CLI Tool in Python: Structure & Typer

Every Python developer eventually writes a script that starts as a single if __name__ == "__main__": block and grows into something that needs subcommands, flags, help text, and configuration. The difference between a script and a real CLI tool is structure: how you parse arguments, how you organize commands, and how you keep the whole thing testable as it grows. This is part one of a three-part series where we build a real CLI tool from scratch. By the end of this series you’ll have a tool that’s structured cleanly, reads configuration files, and is published to PyPI so anyone can pip install it. This part covers project structure and argument parsing with Typer. ...

August 4, 2026 · 7 min

Pydantic: Data Validation the Right Way

Every non-trivial Python program has a boundary where untrusted data enters: an API request body, a config file, an environment variable, a row from a CSV. The naive approach is to trust the shape of that data and let KeyError or TypeError surface deep inside your business logic when it doesn’t match. Pydantic moves that failure to the boundary, where it belongs, and gives you a typed, validated object instead of a bag of dicts and hope. ...

July 29, 2026 · 7 min

Python Type Hints in Practice

Python’s type hints are optional, unenforced at runtime, and yet they’ve become one of the most consequential additions to the language since async/await. They don’t make Python statically typed. What they do is give you a shared vocabulary for describing shapes of data, a way to catch entire categories of bugs before your tests do, and editor support that turns “let me go check the implementation” into a tooltip. This article covers the parts of the typing ecosystem you’ll actually reach for, the ones you’ll see in real codebases, and the tools that turn hints from documentation into enforcement. ...

July 27, 2026 · 10 min

The Most Underrated Packages in the Python Standard Library

Every Python developer knows os, json, and collections. Far fewer reach for bisect when they need a sorted insert, or graphlib when they need a dependency order, and end up pulling in a third-party package (or writing worse code by hand) for something the standard library already does well. This is a tour of the modules that don’t get enough credit: what they do, and how they show up in real code. ...

July 24, 2026 · 7 min