pythonpython-3.xyield

# Converting list function to generator using yield

I am trying to convert a for loop into an iterator using yield, but I have failed in my attempts. I don't understand exactly why the `yield` isn't giving me the expected output. Does anyone know what the problem is?

Attempt at using yield:

``````def iteration_order(dimensions):
for dim in range(dimensions):
order = [0, dim, 0]
yield order
for j in range(6):
sgn = 1 if j % 2 == 0 else -1
idx = j % 3
for _ in range(dim if j < 5 else dim-1):
order[idx] += sgn
yield order
``````
``````print(list(iteration_order(2))
>>> [[0, 0, 0], [0, 1, 1], [0, 1, 1], [0, 1, 1], [0, 1, 1], [0, 1, 1], [0, 1, 1]]
``````

The code as it should work (when not using yield):

``````def iteration_order(dimensions):
full_order = []
for dim in range(dimensions):
order = [[0, dim, 0]]
for j in range(6):
sgn = 1 if j % 2 == 0 else -1
idx = j % 3
for _ in range(dim if j < 5 else dim-1):
nxt = list(order[-1])
nxt[idx] += sgn
order.append(nxt)

full_order.extend(order)
return full_order
``````
``````print(iteration_order(2))
>>> [[0, 0, 0], [0, 1, 0], [1, 1, 0], [1, 0, 0], [1, 0, 1], [0, 0, 1], [0, 1, 1]]
``````

Solution

• The problem you see is because you are using that same list for everything. You might yield it with different value, but the generator still has reference to that list and it modifies it, giving you weird output. If you add `.copy()` for each yield, they will be unique lists and will behave as expected:

``````def iteration_order(dimensions):
for dim in range(dimensions):
order = [0, dim, 0]
yield order.copy()
for j in range(6):
sgn = 1 if j % 2 == 0 else -1
idx = j % 3
for _ in range(dim if j < 5 else dim-1):
order[idx] += sgn
yield order.copy()

print(list(iteration_order(2))) # [[0, 0, 0], [0, 1, 0], [1, 1, 0], [1, 0, 0], [1, 0, 1], [0, 0, 1], [0, 1, 1]]
``````