Firstly, it's good practice in Python to mutate OR return, but not both. That said, you were correct to remove the return
.
Secondly, the problem here is how you use extend
, which mutates the list along with l1
, which is the copy of your original list.
If you run your code and print l1
in the loop for debugging:
def times_mut(l,n):
l1= l
for _ in range(2,n-1):
print(l1) # debugging
l.extend(l1)
l = [1,2,3]
times_mut(l,6)
print(l)
You will see that l1
changes like so:
[1, 2, 3]
[1, 2, 3, 1, 2, 3]
[1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3]
[1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3]
even though you don't actually change it. That's because l1
is a "shallow" copy of l
, meaning that it points to the same place in memory. As a result, any change you make on l
it will also appear in l1
.
Why does this not happen in the original code? Because l_original = l + l_original
creates a new list and stores is in the local variable l_original
while the built-in functions like extend, append etc mutate the object.
I would advise that you look at this, this, this and this.
Furthermore, a simple solution would be to use copy.deepcopy
, which basically copies the content of l
and stores it on a new memory space like so:
import copy
def times_mut(l,n):
l_original=copy.deepcopy(l)
for iii in range(2,n+1):
l.extend(l_original)
l = [1,2,3]
times_mut(l,6)
print(l)
output:
[1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3]