3

Possible Duplicate:
What is the difference between slice assignment that slices the whole list and direct assignment?

I don't have money for school so I am teaching myself some Python whilst working shifts at a tollbooth on the highway (long nights with few customers). (BTW: Coursera should be translated to all languages...)

I have read here that if I have a list l:

l = ['a', '', 'b']

and I want to filter out empty strings like so:

l = [c for c in l if c]

or like so:

l = filter(lambda x: x, l)

it is advisable to do this instead:

l[:] = ... # either method 1 or method 2 above

not to "lose" the reference to the first l, especially in case other variables were pointing to it.

My question:

  • Why is it that l[:] denotes "the contents of l" in this case, allowing specifically reassignment to the "same" l, when elsewhere I think of it as a "same size slice", conveniently creating a copy of l for me?

  • Did I misunderstand how to use the l[:] for same-list-reassignments completely?

I thought that if I had an l and I asked for a l[:], the latter was an actual copy of the original l?

Reference: "Learning Python" -> There are a variety of ways to copy a list, including using the built-in list function and the standard library copy module. Perhaps the most common way is to slice from start to finish

Thanks!

Community
  • 1
  • 1
Robottinosino
  • 10,384
  • 17
  • 59
  • 97
  • not quite. This is asking basically what the difference is between l[:] and l[:] = ..., as far as I understand it. – nneonneo Aug 22 '12 at 17:53
  • @MartijnPieters yeah, I think this is probably far enough from that question to be considered a useful standalone question – Phillip Schmidt Aug 22 '12 at 18:09
  • @MartijnPieters I really don't think this question is an exact duplicate. Maybe it could be worded to show emphasis on the difference between x = l[:] and l[:] = x, but this is definitely a different question. You can test that by looking at the answers to the other question and noticing that none of them would adequately answer this one. – Phillip Schmidt Aug 22 '12 at 18:34

3 Answers3

3

There's a difference in Python between getting a slice of a list and setting a slice of a list. Indeed, they are actually separate operations (__getitem__ and __setitem__, respectively). So, what's true for the get case may not be true for set.

In the former case, l[:] means to get a copy of the list (it generates a brand new list which has all the same contents as the old list). In the latter case, l[:] = ... means to set the contents of the list to something else.

nneonneo
  • 171,345
  • 36
  • 312
  • 383
  • "indeed they are actually separate operations (`__getitem__` and `__setitem__` ...) Very nice (+1) – mgilson Aug 22 '12 at 17:56
3

Because a LHS slice operator basically says enumerate through this list and assign something to each index, while a RHS operator says enumerate through this list, and create a new object with the values.

So lets see it in action:

LHS

l[:] = [c for c in l if c!=0]  #ignore how stupid this list comprehension is

basically gets broken down into:

l[0] = l[0] if l[0] != 0
l[1] = l[1] if l[1] != 0
...
l[n] = l[n] if l[n] != 0

So because you're enumerating through it and assigning values, you're not creating any new objects -- just giving new values to the indices of l.

But, on the other hand, doing

l = anything

Changes the reference that the variable l holds. After that, it points to a totally different object in memory.

RHS

Now,

c = l[:]

will give you a copy of l, not a reference to l. This has to be true, because otherwise,

c = l[1:5]

would have to change the value of l if it were to try and use the same object reference as l.

Phillip Schmidt
  • 8,805
  • 3
  • 43
  • 67
2

When using a slice operator on the left-hand side of an assignment, you are telling python to store the sequence on the right-hand side in the selected elements of the list.

In other words, you are not replacing l, you are assigning to the elements within l.

Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343