krishnab - 1 year ago 85
Python Question

Unpacking values from a python 3 `product` iterator built from `zip` iterators

I am converting some code from Python 2 to Python 3. I ran into an issue where some Python 2 builtins used to generate lists, but now generate iterators in Python 3. I wanted to rewrite this code but have not found a way make the program work without converting the iterators to lists, which does not seem very efficient. The question is whether there is a way to make this code work using iterators instead of converting the iterators to lists?

Here is a simplified version of the Python 3 program.

`````` from itertools import product

points = {(1, 1), (0.5, 0.5), (0.75, 0.75)}
labels = range(len(points))

zips = zip(points, labels)
for pair in product(zips,zips):
if pair[0][1] != pair[1][1]:
print("good")
``````

Note, I simplified the
`for`
loop to just print "good." The real program calculates Euclidean distance, but "good" preserves the basic idea.

Further note that in Python 3, the
`zip`
and
`range`
builtins generate and iterators. Then the
`product`
function from
`itertools`
creates an iterator based upon
`zip`
and
`range`
iterators.

When I run this code in Python 3, The loop just ends without ever printing "good," which is not accurate. The code seems to just bypass the loop since I don't think it finds any values in
`pair`
.

The solution that I found was to just convert the variable
`zips`
to a list. So the code looks like.

`````` from itertools import product

points = {(1, 1), (0.5, 0.5), (0.75, 0.75)}
labels = range(len(points))

zips = list(zip(points, labels))
for pair in product(zips,zips):
if pair[0][1] != pair[1][1]:
print("good")
``````

In the modified code things work, but I have lost the nice iterator structure.

So again, the question is whether I can rewrite this code without having to convert the iterators to lists?

Instead of passing `zips` to `product` twice, use the `repeat` argument:
``````for pair in product(zip(points, labels), repeat=2):
Note that `product` will materialize the iterator under the hood anyway. It has to, since it needs to iterate over the elements more than once.