I am looking for a nice way to `zip` several iterables raising an exception if the lengths of the iterables are not equal.

In the case where the iterables are lists or have a `len` method this solution is clean and easy:

```
def zip_equal(it1, it2):
    if len(it1) != len(it2):
        raise ValueError("Lengths of iterables are different")
    return zip(it1, it2)

```

However, if `it1` and `it2` are generators, the previous function fails because the length is not defined `TypeError: object of type 'generator' has no len()`.

I imagine the [`itertools`](https://docs.python.org/3/library/itertools.html) module offers a simple way to implement that, but so far I have not been able to find it. I have come up with this home-made solution:

```
def zip_equal(it1, it2):
    exhausted = False
    while True:
        try:
            el1 = next(it1)
            if exhausted: # in a previous iteration it2 was exhausted but it1 still has elements
                raise ValueError("it1 and it2 have different lengths")
        except StopIteration:
            exhausted = True
            # it2 must be exhausted too.
        try:
            el2 = next(it2)
            # here it2 is not exhausted.
            if exhausted:  # it1 was exhausted => raise
                raise ValueError("it1 and it2 have different lengths")
        except StopIteration:
            # here it2 is exhausted
            if not exhausted:
                # but it1 was not exhausted => raise
                raise ValueError("it1 and it2 have different lengths")
            exhausted = True
        if not exhausted:
            yield (el1, el2)
        else:
            return

```

The solution can be tested with the following code:

```
it1 = (x for x in ['a', 'b', 'c'])  # it1 has length 3
it2 = (x for x in [0, 1, 2, 3])     # it2 has length 4
list(zip_equal(it1, it2))           # len(it1) < len(it2) => raise
it1 = (x for x in ['a', 'b', 'c'])  # it1 has length 3
it2 = (x for x in [0, 1, 2, 3])     # it2 has length 4
list(zip_equal(it2, it1))           # len(it2) > len(it1) => raise
it1 = (x for x in ['a', 'b', 'c', 'd'])  # it1 has length 4
it2 = (x for x in [0, 1, 2, 3])          # it2 has length 4
list(zip_equal(it1, it2))                # like zip (or izip in python2)

```

Am I overlooking any alternative solution? Is there a simpler implementation of my `zip_equal` function?

**Update:**

* Requiring python 3.10 or newer, see Asocia's [answer](https://stackoverflow.com/a/62773251/446149)
* Thorough performance benchmarking and best performing solution on python<3.10: Stefan's [answer](https://stackoverflow.com/a/69485272/446149)
* Simple answer without external dependencies:
Martijn Pieters' [answer](https://stackoverflow.com/a/32954700/446149) (please check the comments for a bugfix in some corner cases)
* More complex than Martijn's, but with better performance: cjerdonek's [answer](https://stackoverflow.com/a/40596355/446149)
* If you don't mind a package dependency, see
pylang's [answer](https://stackoverflow.com/a/61832383/446149)