2

Why would the following two examples have different results? I thought slicing a list would result in a (shallow) copy of the list elements, so a should not be changed in both cases.

>>> a = [1, 2, 3, 4, 5]
>>> a[3: 5] = [0, 0]  # example 1
>>> a
[1, 2, 3, 0, 0]       # elements in the original list are changed
>>> b = a[3: 5]       # example 2
>>> b = [100, 100]
>>> a                 # elements in the original list are unchanged
[1, 2, 3, 0, 0]
GuLearn
  • 1,814
  • 2
  • 18
  • 32
  • 2
    because `b` is its own list - not the same as `a`. use `id(a)` and `id(b)` to print its ids - you see they differ. – Patrick Artner Sep 07 '19 at 21:15
  • @PatrickArtner that's sorta my question, `id(a[3: 5])` would also be different than id(a), i.e. `id(a)`, `id(b)` and `id(a[3:5])` are all unique, but why does `a[3:5]` directly alter `a` while `b` doesn't? – GuLearn Sep 07 '19 at 21:18
  • It does not - `a[3:5] = [....]` does alter `a` - `id(a[3:5])` is a new shallow copied list – Patrick Artner Sep 07 '19 at 21:19
  • @GuLearn because `a[3:5] =` <-- emphasis on the `=` sign--there's an assignment happening to that slice. But `a[3:5]` where no equals sign is involved is not going to modify `a`. – ggorlen Sep 07 '19 at 21:20

3 Answers3

7

List slices are different depending on the context:

a[3: 5] = [0, 0]

This is a slice assignment, which means to assign the values [0, 0] to a section in a. This clearly modifies a.

b = a[3: 5]

This creates a copy of a section of a and assigns it to b. It is unrelated to a. Modifying b won't affect a at all.

Primusa
  • 13,136
  • 3
  • 33
  • 53
  • make sure to specify the copy `b` creates is shallow: e.g. `a[3] = {1,2,3}` `b = a[3: 5]` `a is b` says `False`, but `a[3] is b[0]` says `True` – Pynchia Sep 07 '19 at 21:27
  • @Pynchia you're definitely right but it's not relevant unless you have objects that are mutable. In this case we're dealing with integers, so the finer points about how the underlying objects are the same don't really matter. i.e. doing `a[3] += 1` won't affect `b[0]` – Primusa Sep 07 '19 at 21:30
  • actually, even `a[4] is b[1]` says `True`, even if it's an integer. It's due to the fact that Python optimises the values in memory. But it keeps a ref count so you can delete one and still have the other, e.g. `del b[1]` and still get `a[4]` – Pynchia Sep 07 '19 at 21:36
  • @Pynchia in python integers are immutable so all integers (I think this is the limit but I"m not 100% sure) <= 256 are referred to the same object. So doing something like `a = 256;a is (a + 1 - 1)` will return `True`. But doing something like `a = 257;a is (a + 1 - 1)` will return `False`. – Primusa Sep 07 '19 at 21:42
  • @Pynchia My point is that I can create two entirely new lists, `a = [1]; b = [1]`, and `a[0] is b[0]` will still be `True`. For this use case of integers, something being or not being a shallow copy doesn't matter at all. All OP cares about is modifications on one list affecting the other. For integers this will never happen. On the other hand if OP was dealing with mutable objects in his lists there would be issues like this: https://stackoverflow.com/questions/240178/list-of-lists-changes-reflected-across-sublists-unexpectedly – Primusa Sep 07 '19 at 21:44
5

You confuse slicing with slice assignment. Slicing creates a new list, slice assignment modifies an existing list.

Modifies the list itself:

a = [1, 2, 3, 4, 5]
a[3: 5] = [0, 0]  # example 1

Creates a new list for the sliced part:

b = a[3: 5]       # example 2

Changes the content of b to some other new list

b = [100, 100]

Use id to check if they are identical:

a = [1, 2, 3, 4, 5]
a[3: 5] = [0, 0]  

b = a[3: 5]  
b = [100, 100]

print(id(a),id(b)) # (140150319362488, 140150319364288)
Patrick Artner
  • 50,409
  • 9
  • 43
  • 69
3

Slicing behaves differently depending on whether it is used in an expression (e.g. on the right hand side of an assignment) or in a target / left hand side of an assignment. If slicing created a shallow copy also on the left hand side, it would be impossible to change a slice of a list directly, and the result of the assignment would simply be lost.

Gianluca
  • 536
  • 4
  • 7