Your list_flatten
function mutates the lst1
argument, so you don't really need to return anything. You can call it like this:
L = [1,[2,['a',(3,'b')]],(5,6),([11,22])]
def list_flatten(lst, lst1):
for item in lst:
if isinstance(item, list):
list_flatten(item, lst1)
else:
lst1.append(item)
Lflat = []
list_flatten(L, Lflat)
print(Lflat)
output
[1, 2, 'a', (3, 'b'), (5, 6), 11, 22]
It's recommended to use isinstance
rather than type
because that makes the code more versatile: it will also work with objects derived from list
.
We can re-write the function so that you don't need to pass in lst1
:
def list_flatten(lst, lst1=None):
if lst1 is None:
lst1 = []
for item in lst:
if isinstance(item, list):
list_flatten(item, lst1)
else:
lst1.append(item)
return lst1
Lflat = list_flatten(L)
print(Lflat)
We give lst1
a default value of None
and on the top level of the recursion we re-bind the name lst1
to an empty list to collect the results.
We can't give lst1
a default value of []
. That's because default args are created when the function is compiled, not when the function is called, and if we gave lst1
a default value of []
that same list would get used on every call. It would look like it does what we want the first time we used list_flatten
, but it would not behave as desired on subsequent calls. Here's a short demo.
L = [1,[2,['a',(3,'b')]],(5,6),([11,22])]
def list_flatten(lst, lst1=[]):
for item in lst:
if isinstance(item, list):
list_flatten(item, lst1)
else:
lst1.append(item)
return lst1
Lflat = list_flatten(L)
print(Lflat)
Lflat = list_flatten(L)
print(Lflat)
output
[1, 2, 'a', (3, 'b'), (5, 6), 11, 22]
[1, 2, 'a', (3, 'b'), (5, 6), 11, 22, 1, 2, 'a', (3, 'b'), (5, 6), 11, 22]
As you can see, lst1
has retained its contents from the first call. For more info on this important topic, please see “Least Astonishment” and the Mutable Default Argument. There are times when this behviour is desirable, but in such cases it's wise to add a comment to your code that you're intentionally using a mutable default argument.
Yet another way is to make list_flatten
into a generator, and collect its output into a list:
def list_flatten(lst):
for item in lst:
if isinstance(item, list):
yield from list_flatten(item)
else:
yield item
Lflat = list(list_flatten(L))
print(Lflat)
In recent versions of Python you can replace list(list_flatten(L))
with [*list_flatten(L)]
.
Python 2 doesn't have yield from
, but you can replace that line with:
for u in list_flatten(item):
yield u
If you don't actually need the list you can call the generator like this:
for u in list_flatten(L):
print(u)
output
1
2
a
(3, 'b')
(5, 6)
11
22