Understanding how is a function evaluated using recursion
Steven D'Aprano
steve+comp.lang.python at pearwood.info
Wed Sep 25 20:10:43 EDT 2013
On Wed, 25 Sep 2013 16:24:22 -0700, Arturo B wrote:
> Hi, I'm doing Python exercises and I need to write a function to flat
> nested lists as this one:
>
> [[1,2,3],4,5,[6,[7,8]]]
>
> To the result:
>
> [1,2,3,4,5,6,7,8]
>
> So I searched for example code and I found this one that uses recursion
> (that I don't understand):
>
> def flatten(l):
> ret = []
> for i in l:
> if isinstance(i, list) or isinstance(i, tuple):
> ret.extend(flatten(i)) #How is flatten(i) evaluated?
> else:
> ret.append(i)
> return ret
>
> So I know what recursion is, but I don't know how is
>
> flatten(i)
>
> evaluated, what value does it returns?
You have the source code to flatten right there in front of you. The very
last line says:
return ret
The first line of the function sets:
ret = []
and it is a list which accumulates all the items seen. If you follow the
code with a simple non-nested list:
flatten([1, 2, 3])
flatten sets the return result "ret" to the empty list, then walks the
argument list extracting each item in turn, which results in this
sequence of calls:
ret = []
ret.append(1)
ret.append(2)
ret.append(3)
return ret # [1, 2, 3, 4]
Now if we do the same thing with a nested list:
flatten([1, [2, 3], 4])
the call to flatten does the same thing, walks the input list, only this
time it has a recursive call:
# outer call
ret = []
ret.append(1)
At this point, the item found is a list, so flatten([2, 3]) is called, so
Python drops into into a new call, building a new list called "ret",
leaving the old one untouched:
# inner call
ret = []
ret.append(2)
ret.append(3)
return ret # [2, 3]
At this point Python drops back to the first call again:
# outer call
ret.extend([2, 3])
ret.append(4)
return ret # [1, 2, 3, 4]
But it all together in one chunk, without the commentary:
flatten([1, [2, 3], 4]) =>
# outer call
ret = []
ret.append(1)
flatten([2, 3]) =>
# inner call
ret = []
ret.append(2)
ret.append(3)
return ret # [2, 3]
# outer call
ret.extend([2, 3])
ret.append(4)
return ret # [1, 2, 3, 4]
In principle, you can nest as many function calls as needed. In practice,
Python will stop after 1000 nested calls by default, although you can
tune it up and down.
--
Steven
More information about the Python-list
mailing list