Look at what the function is handed, and at what the step removes, before writing a line
-
If a list or a string, processed one element at a time → base case the EMPTY structure, step on values[1:], answer the neutral element; if the input can be long, pass an index and keep one list for every frame
Example: sum_list([]) is 0; sum_from(values, i) with base case i == len(values) copies nothing
-
If the step removes TWO elements, one at each end → two base cases in one condition, len <= 1, because an odd length ends on one element
Example: is_palindrome('aba') goes to 'b' and stops there
-
If a number decreased by one at each step → base case 0, depth n; and if n can exceed a thousand, this is a loop, not a recursion
Example: factorial(1024) opens 1025 frames; a for loop opens one
-
If a number halved, or a digit peeled off → base case n == 0 or n < 10, depth log2n or the number of digits: keep the recursion, it is the shape of the algorithm
Example: fast power on n=1024: 11 halvings, 12 frames; digit_sum(1234) makes 4 calls
write half = power(x, n // 2) once; calling power twice in the same line throws the saving away
-
If a SORTED list and a value to find → two indices lo and hi, never a slice; base case lo > hi returns -1; calls on mid + 1 and mid - 1
Example: 1000 values in 10 steps, a million in 20
-
If a structure nested to an unknown depth: lists inside lists, folders inside folders → recursion, and nothing else works: the base case is the LEAF, tested with isinstance, and the step combines the results on the elements
Example: deep_sum([1, [2, [3, 4]], 5]) is 15, with three levels no fixed number of loops can walk
-
If the same subproblem comes back many times, as in Fibonacci → a memo dictionary passed as a parameter, lookup first, store just before the return; or the two-variable loop, which beats it
Example: fib(30): 2692537 naive calls, 59 memoised, 29 additions in a loop
if nothing repeats, as in Hanoi, binary search or deep_sum, the dictionary saves nothing
Python has no tail-call elimination and a default limit of 1000 frames. A recursion whose depth equals the size of the data is a loop wearing a costume; a recursion whose problem splits or nests is the real thing.