Back to all tutorials
pythonfunctionsrecursionpython-functions-series

Python Recursion Explained Like Russian Nesting Dolls

Understand recursion in Python using a matryoshka doll analogy. Learn base cases, recursive cases, and common pitfalls with clear examples.

The Spark Engineer 2026-08-25 10 min read

Python Recursion, Explained Like Russian Nesting Dolls

Open a matryoshka doll and you find a smaller doll inside. Open that one, and there's an even smaller doll. You keep going until you reach the tiniest doll that doesn't open at all, that's where the process stops. Recursion in Python works exactly like this: a function that calls a smaller version of itself, until it hits a point where it stops calling and just answers directly.

What Recursion Actually Is

A recursive function is a function that calls itself, working on a smaller piece of the problem each time.

Python
def open_doll(size):    if size == 0:        print("Smallest doll, no more inside")        return    print(f"Opening doll of size {size}"

Output:

Opening doll of size 3 Opening doll of size 2 Opening doll of size 1 Smallest doll, no more inside

The Two Parts Every Recursive Function Needs

Every matryoshka set eventually has a doll that doesn't open. Every recursive function needs the same thing:

  1. Base case: the condition where the function stops calling itself. Without this, you'd be opening dolls forever, an infinite loop that crashes your program.
  2. Recursive case: the part where the function calls itself with a smaller version of the problem.

In the example above,

  • if size == 0 is the base case
  • open_doll(size - 1) is the recursive case.

A Practical Example: Factorial

The classic textbook example is calculating a factorial (5! = 5 × 4 × 3 × 2 × 1).

Python
def factorial(n):    if n == 0:          # base case        return 1    return n * factorial(n - 1)   # recursive case print(factorial(5))  # 120

Here,

  • We have n * factorial(n - 1) (recursive call)
  • When we call factorial(5), Python does not immediately calculate the answer. It keeps calling the function with a smaller number: 5 * factorial(5-1) i.e. 5 × factorial(4)
factorial(5) → 5 × factorial(4) # factorial(4) = 4 x factorial(3) → 5 × 4 × factorial(3) # factorial(3) = 3 x factorial(2) → 5 × 4 × 3 × factorial(2) # factorial(2) = 2 x factorial(1) → 5 × 4 × 3 × 2 × factorial(1) # factorial(1) = 1
  • When n becomes 1, the base case runs and returned 1
if n == 1: return 1

A Real-Life Use Case: Searching Nested Folders

Recursion isn't just a classroom exercise. File systems are naturally nested, folders inside folders, exactly like the dolls.

PYTHON
import os def count_files(folder): total = 0 for entry in os.scandir(folder): if entry.is_file(): total += 1 elif entry.is_dir(): total += count_files(entry.path) # recurse into subfolder return total

Every subfolder is just a smaller version of the same problem: "count the files in this folder." That's exactly why recursion fits it so naturally, some problems are inherently nested, and forcing a non-recursive solution would be more complicated than the recursive one.

The Danger: Forgetting the Base Case

If you forget the base case, or if it's never actually reached, the dolls never stop opening.

PYTHON
def broken(n): return n * broken(n - 1) # no base case! broken(5) # RecursionError: maximum recursion depth exceeded

Python has a default recursion limit (usually 1000) specifically to catch this kind of mistake before it crashes your computer.

Recursion vs. Loops

Anything recursion can do, a loop can technically also do. Recursion tends to read more naturally for problems that are already nested or tree-shaped, like folder structures or family trees. For simple repetition, like printing numbers 1 to 10, a plain loop is usually clearer and uses less memory, since every recursive call adds a new layer to Python's call stack.

What's Next

You now understand functions that call themselves. The final tutorial in this series covers closures and decorators, functions that wrap other functions, the same trick behind popular tools like Flask's @app.route.

...
Share

Discussion & Thoughts

Join the conversation with your Google Account

0 Comments

Sign in to leave a comment

We use 1-click Google authentication to prevent bot spam and verify authentic developer discussions.

Loading discussions...