Home > Mobile >  Function is changing both lists instead of one list based on '0' in Python
Function is changing both lists instead of one list based on '0' in Python

Time:10-26

I'm a bit confused about why both outputs get changed after the restore when surely it should be just one(outputs are illustrated in the notes). Surely just the first one should change? If anyone could give me a suggestion as to why this happens I'd appreciate it

def switcher(y):
    # shifts two characters
    temp = y[0]
    y[0] = y[1]
    y[1] = temp


sub = [[1,2,3],[1,2,3]]
switcher(sub[0])
sub
#[[2, 1, 3], [1, 2, 3]]

#restore
sub[0] = sub[1]
sub
# [[1, 2, 3], [1, 2, 3]]

switcher(sub[0])
sub
#[[2, 1, 3], [2, 1, 3]]

CodePudding user response:

With sub[0] = sub[1] you are defining both lists to be the same object, that's why the subsequent change is applied to both of them. Do sub[0] = sub[1][:] to create a copy, for example (there is more ways of doing this for a list).

CodePudding user response:

When you are doing sub[0] = sub[1], you are assigning the reference to the value at index 1 i.e. [1, 2, 3] in your case to index 0, so ultimately both the lists reside in the same memory location, and change in either makes the corresponding change to the other.

You can verify this using id builtin which represents the memory reference for a given value:

ids after initialization:

>>> sub = [[1,2,3],[1,2,3]]
>>> [id(s) for s in sub]
[1385461417096, 1385461338824]

ids after calling switcher:

>>> switcher(sub[0])
>>> [id(s) for s in sub]
[1385461417096, 1385461338824]

ids after assigning sub[0] = sub[1]:

>>> sub[0] = sub[1]
>>> [id(s) for s in sub]
[1385461338824, 1385461338824]

As you can see, the ids are same after assigning sub[0] = sub[1], both the sub-lists get changed when modifying one of them

CodePudding user response:

The offending line is the assignment

sub[0] = sub[1]

Assignment never copies data.

You are telling Python that the references sub[0] and sub[1] now both point to the same list object in memory (with the content [1,2,3]).

In your specific case this is easily fixed by taking a (shallow) copy of the list on the right hand side of the assignment.

sub[0] = sub[1][:]

CodePudding user response:

You have a problem with references. By defining:

sub = [[1,2,3],[1,2,3]]

you create a list of two different list, but when you do:

sub[0] = sub[1]

you are telling python to copy sub[1] into sub[0] hence for python your new vector will be:

sub <- [ reference_to_memory_where_sub1_is, sub1 ]

To avoid this behaviour you can explicitly tell python to duplicate the objects in memory. You can do this with the module "copy":

import copy

def switcher(y):
    # shifts two characters
    temp = y[0]
    y[0] = y[1]
    y[1] = temp

l1 = [1,2,3]
l2 = [1,2,3]
sub = [copy.deepcopy(l1),copy.deepcopy(l2)]
switcher(sub[0])
print(sub)
#[[2, 1, 3], [1, 2, 3]]

#restore
sub[0] = l1
print(sub)
# [[1, 2, 3], [1, 2, 3]]

switcher(sub[0])
print(sub)
#[[2, 1, 3], [2, 1, 3]]

  • Related