"Recursion isn't magic — it runs on a stack you already met. Every recursive call stacks a frame; the answers come back as those frames unwind. Once you see the stack, recursion stops being mysterious and starts being mechanical."
Recursion Runs on the Call Stack
Back in the Stacks track, you learned the call stack is a real stack of frames, one per active function call. Recursion is simply that stack growing tall: each recursive call pushes a new frame holding its own arguments and local variables, and that frame waits — paused mid-execution — until its recursive child returns. When the base case finally returns, the frames pop one by one, each resuming where it left off and combining the result. The 'going down' is the calls stacking; the 'coming back up' is the stack unwinding. That's the whole mechanism.
Depth Is Space
This is why recursion costs memory, the point from the Complexity track made concrete: a recursion d levels deep keeps d frames on the stack simultaneously, so it uses O(d) space even if it allocates nothing else. For a balanced tree (depth log n) that's negligible. For a chain or a deep linear recursion (depth n), it's O(n) stack — and if n is large, the stack runs out of room. Python caps recursion at about 1000 frames by default and raises RecursionError when you exceed it. That cap is a guardrail, not a suggestion: deep recursion really can crash.
No Free Lunch: Python Has No Tail-Call Optimization
Some languages optimize tail recursion (where the recursive call is the very last thing the function does) by reusing the current frame instead of stacking a new one — turning deep recursion into O(1) space. Python deliberately does not. Guido van Rossum chose to keep stack traces readable instead. So in Python, a recursion that's n deep really uses n frames, full stop. When you have potentially deep recursion (processing a huge list, walking a degenerate tree), the fix is to convert it to iteration with an explicit stack — exactly the stack/recursion equivalence from the Stacks and Graphs tracks. You manage your own stack on the heap, dodging the call-stack limit entirely.
Pippa's Confession
RecursionError processing a long list recursively and my first instinct was sys.setrecursionlimit(1000000) — just raise the ceiling! Dad stopped me: that doesn't add memory, it just lets Python crash harder, sometimes segfaulting the whole interpreter. The real fix was to rewrite the recursion as a loop with my own explicit stack. I learned that the recursion limit is usually telling the truth — the answer is rarely 'raise the limit,' almost always 'stop stacking so deep.'