0

Suppose I want to write a generator, that returns lists, for example to iterate over list permutations. Take the following simple example:

def list_gen():
    foo = [1,2,3,4]
    for i in range(5, 9):
        foo[1] = i
        yield foo


bar = list(list_gen())
print(bar)
bar = [l for l in list_gen()]
print(bar)

for l in list_gen():
    print(l, end=' ')

The output is:

[[1, 8, 3, 4], [1, 8, 3, 4], [1, 8, 3, 4], [1, 8, 3, 4]]
[[1, 8, 3, 4], [1, 8, 3, 4], [1, 8, 3, 4], [1, 8, 3, 4]]
[1, 5, 3, 4] [1, 6, 3, 4] [1, 7, 3, 4] [1, 8, 3, 4] 

So with the for loop everything works as expected, but with list() or list comprehension all values are equal to the last one. As I understand, this is because lists are mutable and all elements of bar are pointing to the same object.

One possible workaround could be bar = [list(l) for l in list_gen()], but it seems rather ugly. Is there a better way to deal with this problem?

ZeitPolizei
  • 481
  • 1
  • 4
  • 10

1 Answers1

1

A simple solution for this specific problem is to return a new list, rather than the foo object.

def list_gen():
    foo = [1,2,3,4]
    for i in range(5, 9):
        foo[1] = i
        yield list(foo)

Disclaimer: I don't use generators a lot, so this could be against best practice. But it solves the problem.

Phil Sheard
  • 2,102
  • 1
  • 17
  • 38
  • And if you wanted to reset the values of `foo` for each loop back to `[1,2,3,4]` you could move that into the `for` loop. Just incase in future you didn't want changes to persist between each `yield`. – Phil Sheard Nov 07 '17 at 16:44
  • Hi @ZeitPolizei - if this solved your issue, can you mark the question as solved? – Phil Sheard Nov 10 '17 at 14:29