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

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

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

Context Managers: The `with` Statement Demystified

You’ve written with open("file.txt") as f: a thousand times. But what does with actually do? Why does the file close even if an exception is raised inside the block? Once you understand the protocol behind it, you can apply the same pattern to database connections, locks, timers, temporary state changes, or anything with a “setup, then guaranteed teardown” shape. The problem with solves Before context managers, resource cleanup looked like this: ...

July 21, 2026 · 5 min

Python Decorators: From Syntax Sugar to Real-World Patterns

If you’ve used Flask, pytest, or Django, you’ve used decorators. @app.route, @pytest.fixture, @login_required: they’re everywhere. But most developers treat them as magic syntax without understanding what’s actually happening. Once you do understand them, you’ll start reaching for decorators in your own code. What a decorator actually is A decorator is just a function that takes a function and returns a function. That’s it. def my_decorator(func): def wrapper(): print("before") func() print("after") return wrapper def say_hello(): print("hello") say_hello = my_decorator(say_hello) say_hello() # before # hello # after The @ syntax is shorthand for exactly that reassignment. This: ...

July 20, 2026 · 5 min