Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What happens when passing a slice as an argument?

Tags:

python

list

slice

I recently came across a problem with slice. Check the following code:

def clean(l):
    for i in range(len(l)):
        l[i] = 0

lst = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
clean(lst[:])
print lst

This code prints out [1, 2, 3, 4, 5, 6, 7, 8, 9, 10].

It seems that l[i] = 0 inside the function has no effect. So I guess that Python is making a copy of the list when passing a slice into the function... then I did another test...

def clean(l):
    for i in range(len(l)):
        print id(l[i])
lst = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
clean(lst)
print
clean(lst[:])

What surprises me is that the output is as follows:

140373225703016
140373225702992
140373225702968
140373225702944
140373225702920
140373225702896
140373225702872
140373225702848
140373225702824
140373225702800

140373225703016
140373225702992
140373225702968
140373225702944
140373225702920
140373225702896
140373225702872
140373225702848
140373225702824
140373225702800

This says that Python is not making a copy of the list but of the reference... This becomes strange. Since the reference inside the function is still pointing to the original list object, why setting the value to 0 has no effect?

like image 761
Wei Avatar asked Dec 28 '25 15:12

Wei


1 Answers

Slicing returns a new container when applied to lists, but the inner items are still the same. When you assign 0 to an index on a sliced list, you're changing value of that new container not the original list.

>>> lis = [1, 2, 3]                                           
>>> lis_1 = lis[:]
>>> lis_1 is lis     # Outer lists are different
False
>>> lis_1[0] is lis[0]
True
>>> lis_1[0] = 10    # This assignment affects only `lis_1` not `lis`.
>>> lis
[1, 2, 3]
>>> lis_1
[10, 2, 3]
>>> 

The above lists contain only immutable items, when your list contains mutable items and you perform an in-place operation on that item then the changes can be seen in all the lists:

>>> lis = [[1], 2, 3]
>>> lis_1 = lis[:]
>>> lis_1 is lis        #Outer container are different
False
>>> lis[0] is lis_1[0]  #But inner lists are same.
True
>>> lis[0].append(10)
>>> lis
[[1, 10], 2, 3]
>>> lis_1
[[1, 10], 2, 3]

From docs:

Some objects contain references to other objects; these are called containers. Examples of containers are tuples, lists and dictionaries. The references are part of a container’s value. In most cases, when we talk about the value of a container, we imply the values, not the identities of the contained objects; however, when we talk about the mutability of a container, only the identities of the immediately contained objects are implied. So, if an immutable container (like a tuple) contains a reference to a mutable object, its value changes if that mutable object is changed.

like image 117
Ashwini Chaudhary Avatar answered Dec 30 '25 04:12

Ashwini Chaudhary