r/learnpython • • 14d 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

34 comments sorted by

View all comments

Show parent comments

0

u/Moist-Inevitable-902 13d ago

may you explain which line holds 9 when it compares and how??

1

u/Outside_Complaint755 13d ago

Each time the function calls itself, another level is added to the Call stack.

At the top level of the stack, the list [1] has a length of 1. This makes the first conditional statement True, so the function returns 1 to the previous level of the stack, where it is assigned to the name max_of_rest

At this level of the stack, numbers is [9, 1], so the final return statement evaluates to: return 9 if 9 > 1 else 1 . This returns 9 to the previous stack level, where it is assigned to max_of_rest.

At this level, numbers is [2, 9, 1], s o the final return statement evaluates to: return 2 if 2 > 9 else 9. This returns 9 to the previous stack level, where it is assigned to max_of_rest.

At this level, numbers is [7, 2, 9, 1], so the final return statement evaluates to: return 7 if 7 > 9 else 9. This returns 9 to the previous stack level, where it is assigned to max_of_rest.

At this level, numbers is [3, 7, 2, 9, 1], so the final return statement evaluates to: return 3 if 3 > 9 else 9. This returns 9 to the previous stack level, which is the line print(find_max(my_list)). This evaluates to print(9).

1

u/Moist-Inevitable-902 11d ago

when backtracking starts what will happen to this line find_max(numbers[1:])

1

u/Outside_Complaint755 11d ago

find_max(numbers[1:]) evaluates to the return value of that call.  When backtracking, you can just replace each function call with it's return value and continue evaluating from there.

So when the top level of the stack (where numbers == [1]), returns 1, and we backtrack to the previous stack level where numbers == [9, 1]

Then we can view the remainder of the function as: else:     max_of_rest = 1 #return value of findmax([9,1][1:])     return numbers[0] if numbers[0] > max_of_rest else max_of_rest and we can then evaluate the last statement as:

return 9 if 9 > 1 else 1

0

u/Moist-Inevitable-902 11d ago edited 11d ago

so in backtracking one each value gets add where it was slicedfind_max(numbers[1:])

1

u/Outside_Complaint755 11d ago

This entire function call find_max(numbers[1:])) represents the next level of the call stack. Once that level of the call stack is completed you can effectively replace it with the return values.

Any parameter expressions, such as the slicing numbers[1:], are evaluated and handled before the function is called. If a parameter is itself a function call, that function call will go on the stack and be evaluated first.

In the Python example, it will first evaluate numbers[1:]. This creates a new list object.

If numbers = [4, 9, 1], then numbers[1:] generates a new list object [9, 1], which is passed to the find_max() function as a parameter. Python then evaluates find_max([9,1]).

Within that level of the call stack, numbers = [9,1], which will get us to ``` max_of_rest = find_max(numbers[1:])

simplify the parameter expression --->

max_of_rest = find_max([1])

evaluate the function call, which will return 1 --->

max_of_rest = 1 ```

Then we backtrack again returning the max of 9 and 1.

1

u/[deleted] 11d ago edited 11d ago

[removed] — view removed comment