Given a list, e.g. x = [True]*20, I want to assign False to every other element.
x[::2] = False
raises TypeError: must assign iterable to extended slice
So I naively assumed you could do something like this:
x[::2] = itertools.repeat(False)
or
x[::2] = itertools.cycle([False])
However, as far as I can tell, this results in an infinite loop. Why is there an infinite loop? Is there an alternative approach that does not involve knowing the number of elements in the slice before assignment?
EDIT: I understand that x[::2] = [False] * len(x)/2 works in this case, or you can come up with an expression for the multiplier on the right side in the more general case. I’m trying to understand what causes itertools to cycle indefinitely and why list assignment behaves differently from numpy array assignment. I think there must be something fundamental about python I’m misunderstanding. I was also thinking originally there might be performance reasons to prefer itertools to list comprehension or creating another n-element list.
As Mark Tolonen pointed out in a concise comment, the reason why your itertools attempts are cycling indefinitely is because, for the list assignment, python is checking the length of the right hand side.
Now to really dig in…
When you say:
The left hand side (
x[::2]) is a list, and you are assigning a value to a list where the value is theitertools.repeat(False)iterable, which will iterate forever since it wasn’t given a length (as per the docs).If you dig into the list assignment code in the cPython implementation, you’ll find the unfortunately/painfully named function
list_ass_slice, which is at the root of a lot of list assignment stuff. In that code you’ll see this segment:Here it is trying to get the length (
n) of the iterable you are assigning to the list. However, before even getting there it is getting stuck onPySequence_Fast, where it ends up trying to convert your iterable to a list (withPySequence_List), within which it ultimately creates an empty list and tries to simply extend it with your iterable.To extend the list with the iterable, it uses
listextend(), and in there you’ll see the root of the problem:and there you go.
Or least I think so… 🙂 It was an interesting question so I thought I’d have some fun and dig through the source to see what was up, and ended up there.
As to the different behaviour with numpy arrays, it will simply be a difference in how the
numpy.arrayassignments are handled.Note that using
itertools.repeatdoesn’t work in numpy, but it doesn’t hang up (I didn’t check the implementation to figure out why):