cstur4
cstur4

Reputation: 1006

Slice in python - is it a copy or just a pointer?

>>> a = [3, 2]
>>> a[0:1][0] = 1
>>> a
[3, 2]

>>> a[0:1] = [1]
>>> a
[1, 2]

What does a[0:1] mean?

  1. If it's a pointer to the range of a, then a[0:1][0] = 1 should change the value of a.
  2. If it's a copy of the range of a, then a[0:1] = [1] shouldn't change the value of a.

I think the result of the two is inconsistent with each other. Could you please help me work out the problem?

Upvotes: 12

Views: 2889

Answers (3)

sshashank124
sshashank124

Reputation: 32189

The following statement:

>>> a[0:1] = [1]

assigns the list [1] as a subset of the list a from 0 to 1.

By doing a[0:1][0] you are getting the first element of [3] which is 3. Then if you try to assign it a value of 1, it simply wont work because 3 cannot be 1. However, if you stick to a[0:1], you are getting [3], which can be changed to [1]. Hope that helps

Examples

>>> a = [1,2,3,4]
>>> a[1:4]
[2,3,4]

>>> a[1:4] = [6,5,4,3,2]
>>> a
[1,6,5,4,3,2]

Upvotes: -1

glglgl
glglgl

Reputation: 91049

Internally, this is a big difference:

>>> a = [3, 2]
>>> a[0:1][0] = 1

is a shorthand for

temp = a[0:1]
temp[0] = 1

and is internally expressed as

a.__getitem__(slice(0, 1)).__setitem__(0, 1)

resp.

temp = a.__getitem__(slice(0, 1))
temp.__setitem__(0, 1)

so it accesses a part of the list, making a separate object, and doing an assignment on this object, which is then dropped.

On the other hand,

>>> a[0:1] = [1]

does

a.__setitem__(slice(0, 1), [1])

which just operates on the original object.

So, while looking similar, these expressions are distinct on what they mean.

Let's test that:

class Itemtest(object):
    def __init__(self, name):
        self.name = name
    def __repr__(self):
        return self.name
    def __setitem__(self, item, value):
        print "__setitem__", self, item, value
    def __getitem__(self, item):
        print "__getitem__", self, item
        return Itemtest("inner")

a = Itemtest("outer")
a[0:1] = [4]
temp = a[0:1]
temp[0] = 4
a[0:1][0] = 4

outputs

__setitem__ outer slice(0, 1, None) [4]
__getitem__ outer slice(0, 1, None)
__setitem__ inner 0 4
__getitem__ outer slice(0, 1, None)
__setitem__ inner 0 4

Upvotes: 10

anon582847382
anon582847382

Reputation: 20361

Slicing a list creates a shallow copy- it is not a reference to the original. So when you get that slice, it is not bound to the original list a. Therefore, you can try and change a single element of it, but it is not stored in a variable so no changes will be made to any original list.

To clarify, with the former to you doing __getitem__- accessing part of the list (a copy):

a[0:1][0] = 1

You are editing the slice [0:1], which is a only shallow copy of a, so will not edit a itself.

But with the latter, one is calling __setitem__, which will of course edit the object in-place.:

a[0:1] = [1]

You are directly referring to and editing part of a, so it changes in real-time.

Upvotes: 9

Related Questions