0
def mutation(input_list):
  list_copy = input_list[:]
  list_copy[0] = 10
  input_list = list_copy

# Correctly mutates
sample_list = [0,1,2]
sample_copy = sample_list[:]
sample_copy[0] = 10
sample_list = sample_copy
print(sample_list)

# Incorrectly mutates
sample_list = [0,1,2]
mutation(sample_list)
print(sample_list)

In the top snippet of code, I've made a copy of a list and modified it. I then set the original to the copy and then it works. What confuses me is why doing this process outside of a function works but if I were to do it inside a function (the 2nd snippet of code), it fails?

For reference, the code returns:

[10, 1, 2]
[0, 1, 2]

EDIT: I know that calling input_list[0] = 10 works. I just want to know what makes this different from what I showed above all in memory?

Jaden Wang
  • 126
  • 1
  • 9
  • See https://docs.python.org/3/faq/programming.html#how-do-i-write-a-function-with-output-parameters-call-by-reference. – randomir Nov 05 '17 at 00:16
  • Highly suggested reading: https://nedbatchelder.com/text/names.html. This should give you all the answers you need. – SethMMorton Nov 05 '17 at 00:17
  • 1
    Possible duplicate of [How do I pass a variable by reference?](https://stackoverflow.com/questions/986006/how-do-i-pass-a-variable-by-reference) – randomir Nov 05 '17 at 00:17
  • It worked just fine. The `sample_list` in the global namespace did not get mutates.your last line in the function effectively does nothing. `input_list = list_copy` it simply assigns to the local variable `input_list`, but that doesn't affect anything in the global scope. Please read https://nedbatchelder.com/text/names.html – juanpa.arrivillaga Nov 05 '17 at 00:20

3 Answers3

4

In mutation, input_list starts out pointing at the same object as sample_list, but later you make it point at list_copy. sample_list is not modified. It is still pointing at the original object.

When you do it outside of the function you change sample_list to point to the new object before printing it.

Wodin
  • 3,243
  • 1
  • 26
  • 55
1

I think that using the built-in function id to show the object ID will help here. If the ID of two variable names gives the same result then they refer to the same object; otherwise the objects are different.

>>> def mutation(input_list):
...     print(id(input_list))
...     list_copy = input_list[:]
...     print(id(list_copy))
...     input_list = list_copy
...     print(id(input_list))
...     
>>> a = list(range(10))
>>> print(id(a))
140737233394376
>>> mutation(a)
140737233394376
140737233289160
140737233289160

In the above, we see that after input_list = list_copy, the name input_list refers to identically the same object in memory as list_copy, which means it no longer refers to the list given as the function argument. This is why the mutation you expect does not work - you are modifying an entirely different object.

SethMMorton
  • 45,752
  • 12
  • 65
  • 86
0

That's because you sets new value for input_list which is local variable of mutation function.

The simplest solution is changing value of first element of list passed as argument:

def mutation(input_list):
    input_list[0] = 10

Otherwise you can write function which changes value of global variable called sample_list

def mutation():
    global sample_list
    list_copy = sample_list[:]
    list_copy[0] = 10
    sample_list = list_copy
domandinho
  • 1,260
  • 2
  • 16
  • 29