Recursion

A base case, a smaller call, and the call stack.

A recursive function calls itself on a smaller input and stops at a base case. The call stack holds the unfinished frames.

Goal

Write factorial and a recursive sum, and print both.

Base case first

def factorial(n):
    if n < 0:
        raise ValueError("n must be >= 0")
    if n <= 1:
        return 1
    return n * factorial(n - 1)

print(factorial(0))
print(factorial(5))

factorial(5) waits for factorial(4), and so on, until 1.

Recursion vs a loop

def sum_r(xs):
    if not xs:
        return 0
    return xs[0] + sum_r(xs[1:])

def sum_i(xs):
    acc = 0
    for x in xs:
        acc += x
    return acc

nums = [12, 7, 2]
print(sum_r(nums), sum_i(nums))

Same answer. The loop uses constant extra space. The recursive version builds n frames — fine for a kiosk list, not for a million rows.

Countdown

def countdown(n):
    if n <= 0:
        print("open")
        return
    print(n)
    countdown(n - 1)

countdown(3)
Pitfall

Missing base case → RecursionError. The smaller call must actually get smaller (n - 1, xs[1:]), not the same n.