If Python slice copy the reference, why can't I use it to modify the original list?

前端 未结 3 636
野性不改
野性不改 2021-01-21 03:48

I know that Slicing lists does not generate copies of the objects in the list; it just copies the references to them.

But if that\'s the case, then why doesn\'t this wor

相关标签:
3条回答
  • 2021-01-21 04:25

    For the sake of explaining it better, assume you had written

    l = [1, 2, 3]
    k = l[0:2]
    k[-1] = 10
    

    I hope you can agree that this is equivalent.

    Now let's break down the individual statements:

    l = [1, 2, 3]

    This creates the following objects and references:

    id  object
    --  --------
    0   <int 1>
    1   <int 2>
    2   <int 3>
    3   <list A>
    
    name  →  id
    ----     --
    l     →  3
    l[0]  →  0
    l[1]  →  1
    l[2]  →  2
    

    k = l[0:2]

    This creates a new list <list B> containing copies of the references contained in l:

    id  object
    --  --------
    0   <int 1>
    1   <int 2>
    2   <int 3>
    3   <list A>
    4   <list B>
    
    name  →  id
    ----     --
    l     →  3
    l[0]  →  0
    l[1]  →  1
    l[2]  →  2
    k     →  4
    k[0]  →  0  (copy of l[0])
    k[1]  →  1  (copy of l[1])
    

    k[-1] = 10

    First, index −1 resolves to index 1 (because k has length 2), so this is equivalent to k[1] = 10. This assignment means that the objects and references are updated as such:

    id  object
    --  --------
    0   <int 1>
    1   <int 2>
    2   <int 3>
    3   <list A>
    4   <list B>
    5   <int 10>
    
    name  →  id
    ----     --
    l     →  3
    l[0]  →  0
    l[1]  →  1
    l[2]  →  2
    k     →  4
    k[0]  →  0
    k[1]  →  5
    

    Note how l and l[0] to l[2] are not affected by this. QED.

    0 讨论(0)
  • 2021-01-21 04:39

    You are right that slicing doesn't copy the items in the list. However, it does create a new list object.

    Your comment suggests a misunderstanding:

    # Attempting to modify the element at index 1
    l[0:2][-1] = 10
    

    This is not a modification of the element, it's a modification of the list. In other words it is really "change the list so that index 1 now points to the number 10". Since your slice created a new list, you are just changing that new list to point at some other object.

    In your comment to oldrinb's answer, you said:

    Why are l[0:1] and l[0:1][0] different? Shouldn't they both refer to the same object, i.e. the first item of l?

    Aside from the fact that l[0:1] is a list while l[0:1][0] is a single element, there is again the same misunderstanding here. Suppose that some_list is a list and the object at index ix is obj. This:

    some_list[ix] = blah
    

    . . . is an operation on some_list. The object obj is not involved. This can be confusing because it means some_list[ix] has slightly different semantics depending on which side of the assignment it is on. If you do

    blah = some_list[ix] + 2
    

    . . .then you are indeed operating on the object inside the list (i.e., it is the same as obj + 2). But when the indexing operation is on the left of the assignment, it no longer involves the contained object at all, only the list itself.

    When you assign to a list index you are modifying the list, not the object inside it. So in your example l[0] is the same as l[0:2][0], but that doesn't matter; because your indexing is an assignment target, it's modifying the list and doesn't care what object was in there already.

    0 讨论(0)
  • 2021-01-21 04:42

    Slicing a list returns a new shallowly-copied list object. While you are correct that it does not deep-copy the original list's items, the result is a brand new list distinct from the original.

    See the Python 3 tutorial:

    All slice operations return a new list containing the requested elements. This means that the following slice returns a shallow copy of the list:

    >>> squares = [1, 4, 9, 16, 25]
    >>> squares[:]
    [1, 4, 9, 16, 25]
    

    Consider

    >>> squares[:] is squares
    False
    
    0 讨论(0)
提交回复
热议问题