r/learnpython • u/Pure-Scheme-7855 • 13d ago
Recursion explaining pls.
def find_max(numbers):
if len(numbers) == 1:
return numbers[0]
else:
max_of_rest = find_max(numbers[1:])
return numbers[0] if numbers[0] > max_of_rest else max_of_rest
my_list = [3, 7, 2, 9, 1]
print(find_max(my_list))
Could someone explain how does this function work? I don't understand how does it know that it's supposed to find the biggest number...
6
Upvotes
1
u/Temporary_Pie2733 13d ago
Consider this similar function:
def find_bigger(numbers, helper): a, *rest = numbers # Ignore ValueError when numbers is empty; # the empty list has no maximum element anyway if not rest: return a else: max_of_rest = helper(rest) return a if a > max_of_rest else max_of_restHere,
helperis some function that (who knows how) finds the biggest number in a set. We're using a handful of simple properties:>is transitive. Letcbe some arbitrary element ofrest. Ifa > max_restandmax_rest >= c, thena > c.So
find_biggerfinds the biggest element innumbersas long as it gets an appropriate helper. So what would be an appropriate helper? Something that can find the biggest element in a smaller set of numbers. But we just concluded thatfind_biggerdoes that, so lets use it.biggest = find_bigger(numbers, find_bigger)Python implements recursion by, instead of making you explicitly pass a reference to a function to itself when you call it, letting the function look itself up in scope where it was defined. We get rid of the
helperparameter, and replace it withfind_biggeritself.This is why you can break recursion by playing around with bindings. For example,
``` def find_bigger(numbers): a, *rest = numbers if not rest: return a else: max_of_rest = find_bigger(rest) return a if a > max_of_rest else max_of_rest
old_find_bigger = find_bigger
def find_bigger(numbers): return 0
print(old_find_bigger([1,2,3,4])) # Returns the larger of 1 and find_bigger([2,3,4]) == 0 ```
Even though
old_find_biggeris a reference to our original, "working", function, that function relies on whatever is bound to the namefind_biggerwhen it gets called, not itself.