Write a recursive function that sums a list, and show how the calls unwind.
Every recursive function needs two things. It needs a base case that stops the recursion, and it needs a recursive case that calls the function again with a smaller problem.
def total(values):
if not values: # base case
return 0
return values[0] + total(values[1:])
print(total([1, 2, 3, 4])) # 10The call total([1, 2, 3, 4]) adds the first element to the result of total([2, 3, 4]), which adds 2 to the result of total([3, 4]), which adds 3 to the result of total([4]), which adds 4 to the result of total([]). The empty list is the base case, and it returns 0. The calls then unwind in the opposite order, and each frame adds its own element to the value that the frame below it returned, until the outermost call finally returns 10.
Each of those calls is a stack frame that holds its own arguments and its own local variables. The frames are pushed when the call is made and popped when the call returns, and the total memory that is used grows with the depth of the recursion.
There are two things to notice in this implementation. The list slicing on each call does a lot of work, so the whole function is much slower than it looks. And Python's own recursion limit would stop a deep recursion long before a large list became a real problem. A cleaner version takes an index instead of slicing.
def total_index(values, index=0):
if index == len(values):
return 0
return values[index] + total_index(values, index + 1)
This version does the work in one pass, and the price is one extra parameter.