Since this is not a rare assumption for you, then you should have no trouble coming up with some concrete examples of how and when you would use it.
Well, my use cases are "anytime the iterables should be the same length", which several on this thread have agreed is easily the majority of the time they use `zip`. So coming up with examples is more like being asked "When do you use `zip` with what should be equal-length iterables?", or "When do you use the `int` constructor with its default `base=10`?", or "When do you want the RHS values of a `dict.__ior__` to overwrite the LHS on conflicting keys?". Uh... most of the time I use each of those functions? :) As I've said several times, zip's default behavior is a Good Thing, but silently omitting data is a big part of that, and its dangerous enough that I think a straightforward check for "valid" input would be very, very valuable. I understand that your experience differs, though, so here's a handful of situations that would be excellent candidates for the new feature: 1. Likely the most common case, for me, is when I have some data and want to iterate over both it and a calculated pairing:
x = ["a", "b", "c", "d"] y = iter_apply_some_transformation(x) for a, b in zip(x, y): ... ... # Do something. ...
This can be extrapolated to many more cases, where x and/or y are constants, iterators, calculated from each other, calculated individually, passed as arguments, etc. I've written most of them in production code, and in every case, mismatched lengths are logic errors that should "never" happen. A `ValueError` which (a) kills the job, (b) logs the bad data and proceeds to the next job, or (c) alerts me to my error in an interactive session or unit/property test is always better than a silently incomplete result. 2. This is less-well-known, but you can lazily unzip/"transpose" nested iterables by unpacking into `zip`. I've seen it suggested many times on StackOverflow:
x = iter((iter((0, 1, 2)), iter((3, 4, 5)), iter((6, 7, 8)))) y = zip(*x) tuple(y) ((0, 3, 6), (1, 4, 7), (2, 5, 8))
It's clearly a logic error if one of the tuples in `x` is longer/shorter than the others, but this move would silently toss the data instead. 3. Just to show that this has visible effects in the stdlib: below is the AST equivalent of `eval("{'KEY WITH NO VALUE': }")`. The use of `zip` to implement `ast.literal_eval` silently throws away the bad key, instead of complaining with a `ValueError` (as it typically does for malformed or invalid input).
from ast import Constant, Dict, literal_eval malformed = Dict(keys=[Constant("KEY WITH NO VALUE")], values=[]) literal_eval(malformed) {}
So it's not a difficult mistake to make.
...it seems to me that you are incorrect, zip does not already handle the case of unequal iterators internally.
Yeah, I misspoke here. In my defense, though, I've made this point several times, and in those cases I was careful to note that it handles *most of* the logic (you're right that one additional iterator pull is required if the first iterable is the "short" one). My point was not that this change is a one-liner or something, but rather that it doesn't require significant changes to the `zip.__next__` logic and should be effectively no-overhead for strict and non-strict users alike in all but the most pathological cases. Even more important: it's dead-simple to read, write, understand, and maintain. I don't feel the same can be said of sentinels and zip_longest.
I know that I, and everyone on my team, would use it frequently! Use it frequently for what? "We would use it!" is not a use-case. How would you use it?
Well, the comment I was replying to wasn't asking for a use-case, or even arguing against the proposal. They were just asserting that few would use it if it wasn't the default behavior. I felt the need to speak up that, yes, *most* of the engineers I interact with regularly certainly would. But now it's been quoted more times than any of my actual comments on the proposal, so shame on me for the poor wording which doesn't quote well. For use-cases, see above.