krishnab krishnab - 23 days ago 6
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?

Answer

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.