8

I was asked this for a coding test and didn't know the answer. Anyone have any ideas?

Retsam
  • 30,909
  • 11
  • 68
  • 90
user701632
  • 489
  • 3
  • 19

3 Answers3

10

[:] is the slice operator.

When it's on the left side, it overwrites the contents of the list without creating a new reference.

When it's on the right side, it creates a copy of the list with the same contents.

recursive
  • 83,943
  • 34
  • 151
  • 241
  • Ohhh ok it makes sense now. To clarify, id(a) doesn't change when doing a[:] = b. id(a) changes when doing a = b[:]. Is there a reason why one may be better than the other? – user701632 Aug 11 '11 at 22:26
  • Yes, you've got it exactly. If `c` also refers to the same list as `a`, then you might want to change the contents, so that both variables refer to the updated list. – recursive Aug 11 '11 at 22:28
3

a = b[:] calls either __getslice__ or __getitem__ on b and assigns the result to a. In nearly all cases (e.g. lists, tuples, and other sequence types), this makes a shallow copy of the sequence; I don't know of any classes that don't implement that behavior, but you could have a user-defined type that did something different. Any other objects that previously referred to the old value of a will continue to refer to that old value.

a[:] = b, on the other hand, calls __setslice__ or __setitem__ to replace a subset of the elements of a with those of the sequence b. In this case, if the sequence type of a is well-behaved, this will replace the entirety of a, since the range : without endpoints indicates the entire sequence. The difference here is that immutable types, such as tuples, will not allow you to perform __setslice__ (e.g. by throwing a TypeError exception). Any other objects that previously referred to a will also be updated, since the underlying object is being modified.

For mutable types such as list, the result of a = b[:] will be identical to a[:] = b, in that a will be a shallow copy of b; for immutable types such as tuple, a[:] = b is invalid. For badly-behaved user-defined types, all bets are off. There's also a difference in what happens to other objects that referred to the same object as a -- with a = b[:], they refer to the original value (a), but with a[:] = b, they refer to the modified object (shallow copy of b).

Adam Rosenfield
  • 390,455
  • 97
  • 512
  • 589
2

In both cases you end up the list a being a copy of the list b. But the method used to accomplish this has changed.

a[:] = b modifies the list a so that it has the same elements as b

a = b[:] produces a new list which is a copy of b and replaces the list a

The difference is whether we've modified an existing list or created a new one.

To see the difference:

a = range(3)
b = range(4)
c = a # c and a now share the same list
a[:] = b
print "a", a
print "b", b
print "C", c

All three lists will print out the same. C and a share the same object, so when a was modified so was c

a = range(3)
b = range(4)
c = a # c and a now share the same list
a = b[:]
print "a", a
print "b", b
print "C", c

Now c will not print out the same as a. After the assignment, a and c did not share the same object.

Speedwise, a[:] = b is probably a little faster than a = b[:]. The first form doesn't have to create a new list object, it can merely modify the existing list. A big part of this is that it can reuse the memory already owned by the list rather then allocating new memory.

outis
  • 75,655
  • 22
  • 151
  • 221
Winston Ewert
  • 44,070
  • 10
  • 68
  • 83