0

I read here and have learned through bad code that there are problems iterating over lists and changing the list elements within the loop. They suggest one method is to create a copy of the list as such:

for x in a[:]: # make a slice copy of the entire list
    if len(x) > 6: a.insert(0, x)

Does referring to a slice of a list create a temporary copy created for execution of the loop?

What about in the following case found here:

somelist[:] = [x for x in somelist if not determine(x)]

In this case instead of assigning the solution to a new list, they assign output to a slice of the input list. What is the order of operations here which allows this to be done? Why do we not run into the same errors mentioned when modifying list elements through usual for loops?

Community
  • 1
  • 1
blythe10
  • 47
  • 3

2 Answers2

2

There are 2 different methods being called here (__getitem__ vs. __setitem__1). It doesn't have anything to do with order of operations, but the context allows python to pick which function should be called. In the latter case, the "slice" is on the left hand side of an assignment statement which is what causes __setitem__ to be called.

These methods can do anything that you want -- In the case of a list, __getitem__ when called with a slice object makes a copy of that particular portion of the list and __setitem__ when called with a slice causes the right-hand-side to be inserted into that slice.

1There are also the now deprecated __setslice__ and __getslice__ methods

mgilson
  • 300,191
  • 65
  • 633
  • 696
  • In the example above, is __setitem__ called only after the right hand side has finished evaluating and generated a new list? If __setitem__ was called for each iteration in the second example, we would run into the errors I was initially concerned about. EDIT: similarly is __getitem__ called only once when beginning the loop in the first example? – blythe10 Feb 10 '14 at 02:31
  • @blythe10 -- The right hand side is always evaluated first (http://docs.python.org/2/reference/simple_stmts.html#assignment-statements). Then the left hand side is evaluated. You could get into some funky situations if the rhs is a generator expression which relys on the object on the left hand side though. – mgilson Feb 10 '14 at 02:50
2

The syntax someList[:] means slightly different things depending on whether it occurs on the left-hand side of an assignment or not.

By itself, someList[:] indeed creates a (shallow) copy.

someList[:] = ... causes the expression on the right to replace the existing contents of the list. No copy is created. The contents of the existing list are modified.

You can also look at it as someList[:] always means the same thing, which is "the contents of the list". someList[:] by itself creates a copy, because it gives you the contents of the list, not the list itself, and so it has to create a new list to "hold" those contents. Assigning to someList[:] overwrites the list, because it replaces the contents of the existing list.

BrenBarn
  • 242,874
  • 37
  • 412
  • 384