The function as posted returns/exits when running into a first bottom-down list-element which doesn't contain a list - this prevents walking all the further branches of the recursion. For example:
print( f([1, [[2, 'a', [3, 'b', [4, 'c']]], ['a','b']], (3, 4)]) )
# gives: [4, 'c']
print( f([1, ['X','Y'], [[2, 'a', [3, 'b', [4, 'c']]], ['a','b']], (3, 4)]) )
# gives: ['X','Y']
The key point causing this behaviour is the line
result = []
This resets the list with results on each call of the function to an empty list. This way only one item is returned up from the chain of the recursion calls.
By the way the function f below does what you have expected, doesn't it?
def f(L, result):
for e in L:
if type(e) != list:
result.append(e)
else:
f(e, result)
result=[]; f([1, [[2, 'a', [3, 'b', [4, 'c']]], ['a','b']], (3, 4)], result) print( result )
# gives: [1, 2, 'a', 3, 'b', 4, 'c', 'a', 'b', (3, 4)]
result=[]; f( [1, ['X','Y'], [[2, 'a', [3, 'b', [4, 'c']]], ['a','b']], (3, 4)], result); print( result )
# gives: [1, 'X', 'Y', 2, 'a', 3, 'b', 4, 'c', 'a', 'b', (3, 4)]
NOTICE: (3,4) is a TUPLE not a list ...
The function f as above collects items from a list if these items are not a list themselves. In the special case, when the item in the list is a list, the function calls itself to collect the items from this list. This way all they way down of the hierarchy every element is collected, no matter how deep one needs to dig down. This is the beauty of recursion - a function calling itself does the 'magic' of visiting all of the branches and their leaves down a tree :)