1

While trying to implement an algorithm, I couldn't get python lists to mutate via a function. After reading up on the issue I was suggested by this StackOverflow answer to use [:] in order to mutate the array passed in the function argumemt.

However, as seen in the following code snippet, the issue still persists when trying to mutate the list l. I am expecting the output to be Before: [1,2,3,4] After: [69, 69, 69, 69], but instead I get back the original value of l as shown below.

def mutate_list(a, b):
    c = [69] * 4
    a[:] = c[:2]  # changed the elements, but array's still unchanged outside function
    b[:] = c[2:]

if __name__ == '__main__':
    l = [1, 2, 3, 4]
    print("Before: {}" .format(l))
    mutate_list(l[:2], l[2:])
    print("After: {}" .format(l))

Output:

Before: [1, 2, 3, 4]
After : [1, 2, 3, 4]

Any insights into why this is happening?

petezurich
  • 9,280
  • 9
  • 43
  • 57
babrar
  • 179
  • 2
  • 14

3 Answers3

2

The error is that you not pass actually the l but two slices of it. You should change it, for example:

def mutate_list(a):
    c = [69] * 4
    a[:2] = c[:2]
    a[2:] = c[2:]

if __name__ == '__main__':
    l = [1, 2, 3, 4]
    print("Before: {}" .format(l))
    mutate_list(l)
    print("After: {}" .format(l))
Giannis Clipper
  • 707
  • 5
  • 9
0
  1. its all about the scope, mutable concept is applicable on list but not to reference variable.

The variables a,b are local variables, hence the scope of the variable will be always function scope.

  1. The operations which you have performed :

    a[:]=c[:2]

    b[:]=c[2:]

Note: a and b both are list now so you will get following output in the function:

[69,69],[69,69]

but if you use + operator which is use for adding operations then the out out will be like:

[69,69,69,69]

Now whatever I told you that will be a local scope, if you want that the list should be mutable across the program then you have to specify the scope of the list as global inside function and on that variable you can do changes. in this case you also dont need to pass any arguments:

def mutate_list():

global l # telling python to use this global variable in a local function

c = [69] * 4

l=c      # assigning new values to actual list i.e l

Now before output will be [1,2,3,4]

and after will be [69,69,69,69]

The Guy
  • 411
  • 4
  • 11
0

As pointed out by others, the issue arose from the fact that the function parameters were slices of the original array and as such, the parameters were being passed by value (instead of being passed by reference).

According to @Selcuk 's suggestion, the correct way of doing such an operation would be to pass the original array along with its indices to the function and then perform any slicing inside the function.

NOTE: This concept comes in handy for (recursive) divide-and-conquer algorithms where subarrays must be mutated and combined to form the solution.

babrar
  • 179
  • 2
  • 14