Recursion and Fractals¶
By the end of this lesson you'll be able to:
- Explain what recursion is and why every recursive function needs a base case
- Trace through a simple recursive function step by step
- Write a lambda (one-line anonymous function) and pass functions as arguments
- Build a recursive fractal tree using turtle graphics
Recursion is one of the most mind-bending ideas in programming — a function that calls itself. Once you understand it, you'll see fractals in a completely new way.
Welcome to Chapter 24!
Recursion sounds scary, but it's really just a function that knows how to break a big problem into a smaller version of the same problem.
Let's start simple, then build something beautiful. Let's code it together!
The Recursion Concept¶
Recursion happens when a function calls itself. Think about Russian nesting dolls — each doll contains a smaller version of itself, all the way down to the tiny solid one at the center.
The solid doll at the center is the base case — the point where the function stops calling itself.
Without a base case, the function would call itself forever (or until Python runs out of stack space and raises a RecursionError).
The simplest recursive example is counting down:
1 2 3 4 5 6 | |
The Base Case¶
Every recursive function must have a base case. The base case is the condition that stops the recursion and returns a value without calling the function again.
If you forget the base case, Python eventually raises RecursionError: maximum recursion depth exceeded after about 1000 nested calls.
A well-designed recursive function: 1. Checks for the base case first 2. Makes the recursive call with a smaller or simpler version of the input
Recursion Depth and the Call Stack¶
Each time a function calls itself, Python saves the current state in memory (the call stack). This means recursion uses memory — and Python limits the stack to about 1,000 levels deep by default.
For most student programs this is plenty. But for very deep recursion (like large fractals), you may need to reduce the depth.
What Do You Think Will Happen?
The recursive factorial function below computes n! (n factorial).
What do you think factorial(5) returns? Remember: 5! = 5 × 4 × 3 × 2 × 1.
Make your guess — then run it!
Were you right? 5! = 120. Tracing it: 5 * factorial(4) → 5 * 4 * factorial(3) → ... → 5 * 4 * 3 * 2 * 1.
See It: The Call Stack in Action¶
What Do You Think Will Happen?
Every recursive call gets its own frame on a stack, each remembering
its own n. For factorial(4), predict: how tall will the tower of
frames get before it starts coming back down? Step through and count!
Explore the Recursion Call Stack MicroSim
Watch the two phases: frames pile up with paused multiplications (4 × ?) until the gold base case, then the answers flow back down as each frame finishes its math. Then pick Missing Base Case from the dropdown to see exactly why every recursive function needs a stopping rule.
Lambda Functions¶
A lambda is a tiny anonymous function written on one line.
The syntax is: lambda parameters: expression.
1 2 3 4 5 | |
Lambdas are most useful when you need a short function as an argument to another function, like sorted(key=...) or map().
Functions as Arguments¶
In Python, functions are first-class objects — you can pass them as arguments to other functions.
Before we try this, note what it means: when a function takes another function as a parameter, the outer function can call it on any input without knowing what it does in advance.
1 2 3 4 5 6 | |
Nested Functions¶
You can define a function inside another function. The inner function can access variables from the outer function.
The nonlocal keyword lets an inner function modify a variable from its enclosing (outer) function — similar to how global lets a function modify a global variable.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | |
Fractals with Recursion and Turtle¶
A fractal is a pattern that repeats itself at smaller and smaller scales. Recursive functions are perfect for drawing fractals because each branch is a smaller version of the whole.
The fractal tree works like this: draw a trunk, then at the top of the trunk, draw two branches at angles — and each branch is a smaller tree.
Before the code, the key parameters are:
- length — length of the current branch
- angle — how far each branch spreads left and right
- When length < 5, stop drawing (base case)
Try changing the angle from 25 to 35 or 15 to see how it changes the tree's shape!
The Magic of Backtracking
Notice t.backward(length) at the end of draw_tree. This is the turtle going back to where it started before it drew the current branch.
Without this, the turtle would wander off. Backtracking is what makes recursive drawing work — always return the turtle to where you found it.
See It: Sculpt a Fractal with Sliders¶
Editing the turtle code and re-running works, but sliders reveal how sensitive a fractal is to its parameters. In the explorer below, every recursion level has its own color — the brown trunk is level 0, and the greenest twigs are the deepest calls. Before you drag anything, predict: what happens to the "recursive calls" counter each time you raise the depth by 1?
Explore the Fractal Tree Explorer MicroSim
Roughly doubles every time — that is the two-recursive-calls pattern you just wrote in draw_tree. When you find a tree you love, click Snapshot, keep exploring, and compare against the gray ghost. Can you design a weeping willow? A tumbleweed?
Learning Check¶
Your Turn — Add Color to the Fractal Tree
The fractal tree draws in the default color. Modify the draw_tree function so that:
- Branches with length >= 40 are drawn in "brown" (trunk/main branches)
- Shorter branches (length < 40) are drawn in "green" (leaves)
Add a t.pencolor() call at the start of the function to set the color based on length.
Experiments¶
Try these changes. Predict what will happen first, then run it to check!
-
Change the
0.7multiplier indraw_treeto0.6. The tree will branch faster. You'll know it worked when the tree is shorter and bushier. -
Change the angle from
25to40. You'll know it worked when the branches spread out much wider. -
Write a recursive function
sum_list(lst)that adds up all items in a list without using Python'ssum(). You'll know it worked whensum_list([1, 2, 3, 4, 5])returns15. -
Write a recursive function
reverse_string(s)that reverses a string. Base case: iflen(s) <= 1, returns. Otherwise returnreverse_string(s[1:]) + s[0]. You'll know it worked whenreverse_string("hello")returns"olleh". -
Use a lambda with
sorted()to sort["banana", "apple", "fig", "kiwi"]by string length. You'll know it worked when shorter words appear first.
Recursion Master!
You've grasped one of the most powerful and beautiful ideas in all of programming!
Recursion, fractals, lambdas, and functions-as-arguments — these concepts appear in professional code every day.
Next up: object-oriented programming! Let's keep coding!