Lists the difference between generators and loops
Looking at this answer , It seems that using list understanding (or for
loops versus append
) is equivalent to calling list(..)
on an iterator. Since generators are iterators and I hope the same is true for generators. However, if you run
def permute(xs, count, low = 0):
if low + 1 >= count:
yield xs
else:
for p in permute(xs, low + 1):
yield p
for i in range(low + 1, count):
xs[low], xs[i] = xs[i], xs[low]
for p in permute(xs, low + 1):
yield p
xs[low], xs[i] = xs[i], xs[low]
print("Direct iteration")
for x in permute([1, 2], 2):
print(x)
print("Listing")
for x in list(permute([1, 2], 2)):
print(x)
Direct iteration
[1, 2]
[2, 1]
Listing
[1, 2]
[1, 2]
Why is this?
Solution
You are modifying and generating the same list xs
over and over again. When the generator runs, the list contents change. It looks like it works fine because while each print(x) prints
the same list object, the object has different content each time.
On the other hand, the second loop runs the generator until it completes and collects all list references. Then it prints out the list – except that they are all the same list, so every row is the same!
Change the two lines print(x) to print(x, id(x
))
and you’ll see what I mean. The ID numbers will all be the same.
Direct iteration
[1, 2] 140685039497928
[2, 1] 140685039497928
Listing
[1, 2] 140685039497736
[1, 2] 140685039497736
Quick fix is a copy of the list instead of the original. Yield p
is fine, but yield xs
should become:
yield xs[:]
With the fix, the results are as expected:
Direct iteration
[1, 2] 140449546108424
[2, 1] 140449546108744
Listing
[1, 2] 140449546108424
[2, 1] 140449546108808
The result of both loops is the same, with different ID numbers.