I have some reproducible code here:
def test():
a = [0, 1, 2, 3]
for _ in range(len(a)):
a.append(a.pop(0))
for i in range(2,4):
print(a)
yield(i, a)
This prints out:
[1, 2, 3, 0]
[1, 2, 3, 0]
[2, 3, 0, 1]
[2, 3, 0, 1]
[3, 0, 1, 2]
[3, 0, 1, 2]
[0, 1, 2, 3]
[0, 1, 2, 3]
Which is what I expected, but when I do list(test())
I get:
[(2, [0, 1, 2, 3]),
(3, [0, 1, 2, 3]),
(2, [0, 1, 2, 3]),
(3, [0, 1, 2, 3]),
(2, [0, 1, 2, 3]),
(3, [0, 1, 2, 3]),
(2, [0, 1, 2, 3]),
(3, [0, 1, 2, 3])]
Why is this the case, and what can I do to work around it?
The general rule of thumb is that you don't modify a collection/array/list while iterating over it. Use a secondary list to store the items you want to act upon and execute that logic in a loop after your initial loop. Show activity on this post. And it should do it without any errors or funny behaviour.
Modifying a sequence while iterating over it can cause undesired behavior due to the way the iterator is build. To avoid this problem, a simple solution is to iterate over a copy of the list. For example, you'll obtain a copy of list_1 by using the slice notation with default values list_1[:] .
Because you always return (i,a)
now a
is a reference to the list. So you constantly return a reference to the same list. This is no problem for the print
statement, since it immediately prints the state of a
at that moment.
You can return a copy of the list, for instance like:
def test():
a = [0, 1, 2, 3]
for _ in range(len(a)):
a.append(a.pop(0))
for i in range(2,4):
print(a)
yield(i, list(a))
You're yielding the same list every time, so the caller's list simply has a bunch of references to that list, which has been updated each time they called. You need to make copies of the list when you yield:
def test():
a = [0, 1, 2, 3]
for _ in range(len(a)):
a.append(a.pop(0))
for i in range(2,4):
print(a)
yield(i, a[:])
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With