4
my_list = [1, 2] def f(): print my_list yield 11 print my_list yield 22 print my_list my_list[:] = f() print "finally ", print my_list 

output:

[1, 2] [1, 2] [1, 2] finally [11, 22] 

what I expected was:

[1, 2] [11, 2] [11, 22] finally [11, 22] 

Someone once told me slice assignment was in place. Obviously not. Is there an elegant way to achieve it?

2
  • 1
    @BrenBarn are you sure it should be editted from "slice" to "splice" ? Commented Aug 9, 2012 at 5:24
  • 1
    Yes (or rather, from "splice" to "slice"). See, e.g., the documentation at docs.python.org/library/… Commented Aug 9, 2012 at 5:25

2 Answers 2

8

Slice assignment is in-place, but the assignment doesn't happen until the entire generator is consumed. It doesn't assign one element at a time to the list. It reads them all and then sticks them all into the list at once.

(Note that it has to do it this way because you can assign a sequence to a slice even if the sequence is a different length than the original slice. You can do, e.g., x[2:3] = [1, 2, 3, 4, 5, 6]. There's no way to do this by replacing one element at a time, because there's no one-to-one mapping between the old slice and the new sequence that's replacing it.)

There isn't a way to achieve what you want by slice assignment, because slice assignment always works in this all-at-once way. You would have to iterate over the list and the generator in parallel and replace individual elements one at a time.

Sign up to request clarification or add additional context in comments.

1 Comment

Right, It's "in place" in the sense of putting the list into my_list in place, but consuming the generator into a temporary list kind of defeats the "in place" purpose. Thanks, makes sense.
2

It is possible to do this, but not as directly.

Consider:

my_list = [1,2,3,4] def f(): print 'first: ', my_list yield 11 print 'second:', my_list yield 22 print 'third: ', my_list def inplace(l, func): gen=func() for i,x in enumerate(l): try: l[i]=gen.next() except StopIteration: if i<len(l): del l[i:] break inplace(my_list,f) print "final: ", my_list 

Prints:

first: [1, 2, 3, 4] second: [11, 2, 3, 4] third: [11, 22, 3, 4] final: [11, 22] 

Of course, the way it is written, the list will be the shorter of the original list or the elements in the generator.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.