Reputation: 1600
I was trying to solve a problem consisting in finding the max value of a list with several level of depth. I tried several ideas but no luck. So I found this online. I actually had this idea myself but I discarded it without testing it for the reason I'll mention right after.
def get_max(my_list):
m = None
for item in my_list:
if isinstance(item, (list, tuple)):
item = get_max(item)
if not m or m < item:
m = item
return m
Sample run:
>>> get_max(((10, (1,2), [[1],[9]])))
>>> 10
So I did discard this idea because I thought that if the value of m is reset to None at each recursive steps, it's not going to find the max value I need. I ran it in Python Tutor but I still don't understand how m would remember the value 10 as it as been reset to None several times.
Could somebody explain to me please?
Does every recursive step create a new frame somehow?
Upvotes: 0
Views: 453
Reputation: 55479
As others have mentioned your recursion does the right thing because each call of get_max
gets its own local variables, my_list
, m
, and item
.
FWIW, here's a minor variation on your code. It should be a little more efficient because it uses the built-in max
rather than computing the maximum with a Python loop (although we're still looping in that generator expression). It also eliminates the need to do m = None
, and hence the need to test if m
is initialised every time we update it.
def get_max(obj):
is_seq = isinstance(obj, (list, tuple))
return max(get_max(u) for u in obj) if is_seq else obj
data = (10, (1, 2), [[1], [9], [4, 7]])
print(get_max(data))
output
10
We can also write it using map
instead of a generator expression in the max
call.
def get_max(obj):
is_seq = isinstance(obj, (list, tuple))
return max(map(get_max, obj)) if is_seq else obj
Upvotes: 1
Reputation: 2127
The recursive call appears to be for lists within the current list. So, the base case for this function is a list that only contains non-list items. In other words, there is only a new function call, and thus an instance of the m
variable, when a new list is found.
Each call to get_max()
will have its own variable m
which will hold the max value at that level and below.
Upvotes: 0
Reputation: 3442
Does every recursive step create a new frame somehow?
Yes, each recursive call to max
creates a new frame. There are actual ramifications to this (as in: what happens if the recursion depth is very large or possibly infinite? By default, CPython sets the maximum recursion depth to 1000. See also: What is the maximum recursion depth in Python, and how to increase it?)
m is a local variable. So the m in the first parent call of max
is not the same m that is assigned in a child call of max
. The "remembering" is because the child m is returned as item to the parent.
Upvotes: 2