Recursion¶
It is possible for a function to call itself. The act of a function calling itself is called recursion, and a function that uses recursion is referred to as recursive. It might not be immediately obviously what would happen if a function was to call itself, or why this might be useful. In fact, recursions can be a difficult concept to fully understand, but it is none-the-less a very powerful tool for addressing certain types of problems. In this lesson we will discuss how recursion work. We will also provide an indication as to some of the potential uses of recursion.
First Example of Recursion¶
In the cell below, we create a function named countdown()
. Notice that this function calls itself, and is thus recursive.
def countdown(n):
if n <= 0:
print('Blastoff!')
else:
print(n)
countdown(n-1)
We will now call the function, supplying a value of 5 for the parameter n
.
countdown(5)
5
4
3
2
1
Blastoff!
Let’s break down what occurred when we called countdown()
in the previous cell.
We explicitly called
countdown(5)
. Theif
condition did not trigger, so 5 was printed, and thencountdown(4)
was called.Within the call
countdown(4)
, theif
condition did not trigger, so 4 was printed, and thencountdown(3)
was called.Within the call
countdown(3)
, theif
condition did not trigger, so 3 was printed, and thencountdown(2)
was called.Within the call
countdown(2)
, theif
condition did not trigger, so 2 was printed, and thencountdown(1)
was called.Within the call
countdown(1)
, theif
condition did not trigger, so 1 was printed, and thencountdown(0)
was called.Within the call
countdown(0)
, theif
condition triggered, printing'Blastoff!'
. No other functions were called, allowing the recursion to end.
Each new call to countdown()
creates its own local scope that lives inside the local scope from which it was called. Furthermore, none of the function calls are allowed to exit until of its calls that it has created have finished executing. This is demonstrated more clearly in the following example.
Second Recursion Example¶
In the example below, notice that we have included print statements before and after the line that involves recursion. When a function call encounters a call to a function (even itself), it will pause its own execution, and will then process the new call to completion before moving own to later instructions.
def recursion_example(n):
print('Beginning call for n =', n)
if n == 0:
print('We have hit zero!')
else:
recursion_example(n-1)
print('Finishing call for n =', n)
We will now test this function by calling it with n=3
.
recursion_example(2)
Beginning call for n = 2
Beginning call for n = 1
Beginning call for n = 0
We have hit zero!
Finishing call for n = 0
Finishing call for n = 1
Finishing call for n = 2
Since the last print statement in the definition of recursion_example()
occurs after the recursive step, this line does not execute for ANY of the function calls until the recursion ends. At that point, the function calls end in reverse order and the remaining print statements are executed, again, in reverse order.
The diagram below attempts to further explain what happens when we call recursion_example(2)
. The actions described below occur in the order in which they are shown, and lines with the same level of horizontal indentation occur within the same call to recursion_example()
.
Base Case and Infinite Recursion¶
Notice that both of the examples we provided above include an if...else
statement in which one branch causes the function to recurse, and the other branch allows the recursion to end. This is typical of recursive functions. A recursive function will generally have one or more sets of parameter values for which the function does not recurse. Such a set of parameter values is referred to as a base case
for the function. Recursive functions should be written so as to guarantee that they will always encounter a base case. Otherwise, the function might recur infinitely.
Two examples of potentially infinitely recursive functions are provided below. The first function does nothing other than call itself, and there is no condition to keep it from continuing to do so. The second function had a condition that could potentially allow it to stop recurring, but notice that this condition will never be met if an odd number is supplied for the parameter n
.
def to_infinity():
to_infinity()
def infinite_odds(n):
print(n)
if n == 0:
print('Done!')
else:
infinite_odds(n-2)
In truth, Python will not allow infinite recursion. There is a maximum depth at which recursive functions can be stacked. By default, this number is 3000 on most systems. If the number of recursive calls to a function hits this depth, an error message will be displayed saying "maximum recursion depth exceeded"
.