The problem here is you are always using a global variable. Using mutable global scope is generally an anti-pattern. Keeping your code essentially the same. An easy approach is to use an accumulator and pass it as an argument to your recursive calls:
In [4]: def flatten(nested_list, result=None):
...: if result is None:
...: result = []
...: for i in nested_list:
...: if type(i) != list:
...: result.append(i)
...: else:
...: flatten(i, result)
...: return result
...:
...:
In [5]: x = [[1,[2], [3,4],5]]
In [6]: flatten(x)
Out[6]: [1, 2, 3, 4, 5]
In [7]: x
Out[7]: [[1, [2], [3, 4], 5]]
In [8]: flatten(x)
Out[8]: [1, 2, 3, 4, 5]
In [9]: x
Out[9]: [[1, [2], [3, 4], 5]]
Often, though, you don't want to expose result
as a parameter waiting for you to shoot yourself in the foot. So, you can define a "private" helper function:
In [15]: def _flatten(nested_list, result):
...: for i in nested_list:
...: if type(i) != list:
...: result.append(i)
...: else:
...: _flatten(i, result)
...: return result
...:
...: def flatten(nested_list):
...: return _flatten(nested_list, [])
...:
...:
In [16]: x = [[1,[2], [3,4],5]]
In [17]: flatten(x)
Out[17]: [1, 2, 3, 4, 5]
In [18]: x
Out[18]: [[1, [2], [3, 4], 5]]
In [19]: flatten(x)
Out[19]: [1, 2, 3, 4, 5]
Or, you can define your helper inside your main function, and squirrel your result variable in a closure:
In [26]: def flatten(nested_list):
...: result = []
...: def _flatten(nested_list):
...: for i in nested_list:
...: if type(i) != list:
...: result.append(i)
...: else:
...: _flatten(i)
...:
...: _flatten(nested_list)
...: return result
...:
...:
In [27]: flatten(x)
Out[27]: [1, 2, 3, 4, 5]
In [28]: x
Out[28]: [[1, [2], [3, 4], 5]]
In [29]: flatten(x)
Out[29]: [1, 2, 3, 4, 5]