
On Sat, May 2, 2020 at 1:19 PM Steven D'Aprano <steve@pearwood.info> wrote:
But I question whether *enough* people need it *often enough* to make it a builtin, or to put a flag on plain zip.
It has taken years for it to be added to more-itertools, suggesting that the real world need for this is small.
My personal opinion is that given that Brandt has found one concrete use for this in the stdlib
Many (I'd guess most, but it's hard to measure) uses of zip are concrete use cases for a strict zip. Most uses of zip are meant for equal lengths, and unequal lengths are a sign of an error somewhere. People just can't be bothered at the moment to make their zips strict because it's inconvenient. I'm guessing Brandt's ast.unparse example is more significant than just a place where a strict check could be useful. I'm guessing it's an example where he or someone else actually got bit by the lack of a check. Those are hard to find. But I'm pretty sure I've experienced it, and we know Ram has. Something that's a bit easier to find is examples where people have checked lengths directly. These either show that a strict zip could have been used directly, or at least that people are concerned about unequal lengths: https://github.com/more-itertools/more-itertools/blob/master/more_itertools/... if len(iterables) != len(offsets): raise ValueError("Number of iterables and offsets didn't match") staggered = [] for it, n in zip(iterables, offsets): https://github.com/pypa/setuptools/blob/master/setuptools/dep_util.py#L13 if len(sources_groups) != len(targets): raise ValueError("'sources_group' and 'targets' must be the same length") # build a pair of lists (sources_groups, targets) where source is newer n_sources = [] n_targets = [] for i in range(len(sources_groups)): if newer_group(sources_groups[i], targets[i]): https://github.com/gristlabs/asttokens/blob/master/tests/test_mark_tokens.py... self.assertEqual(len(t1), len(t2)) for vc1, vc2 in zip(t1, t2): self.assert_nodes_equal(vc1, vc2) File "cpython/Tools/demo/sortvisu.py", line 348 if len(oldpts) != len(newpts): raise ValueError("can't interpolate arrays of different length") pts = [0]*len(oldpts) res = [tuple(oldpts)] for i in range(1, n): for k in range(len(pts)): pts[k] = oldpts[k] + (newpts[k] - oldpts[k])*i//n File "cpython/Modules/_decimal/libmpdec/literature/fnt.py", line 194 assert(len(a) == len(b)) x = ntt(a, 1) y = ntt(b, 1) for i in range(len(a)): y[i] = y[i] * x[i] https://github.com/matplotlib/matplotlib/blob/master/lib/matplotlib/collecti... if len(verts) != len(codes): raise ValueError("'codes' must be a 1D list or array " "with the same length of 'verts'") self._paths = [] for xy, cds in zip(verts, codes): https://github.com/matplotlib/matplotlib/blob/master/lib/matplotlib/axes/_ax... if len(lineoffsets) != len(positions): raise ValueError('lineoffsets and positions are unequal sized ' 'sequences') if len(linelengths) != len(positions): raise ValueError('linelengths and positions are unequal sized ' 'sequences') if len(linewidths) != len(positions): raise ValueError('linewidths and positions are unequal sized ' 'sequences') if len(colors) != len(positions): raise ValueError('colors and positions are unequal sized ' 'sequences') if len(linestyles) != len(positions): raise ValueError('linestyles and positions are unequal sized ' 'sequences') colls = [] for position, lineoffset, linelength, linewidth, color, linestyle in \ zip(positions, lineoffsets, linelengths, linewidths, colors, linestyles): https://github.com/matplotlib/matplotlib/blob/master/lib/matplotlib/axes/_ax... for e in [a, b]: if len(data) != len(e): raise ValueError( f"The lengths of the data ({len(data)}) and the " f"error {len(e)} do not match") low = [v - e for v, e in zip(data, a)] high = [v + e for v, e in zip(data, b)] https://github.com/matplotlib/matplotlib/blob/master/lib/matplotlib/axes/_ax... if (len(np.ravel(usermedians)) != len(bxpstats) or np.shape(usermedians)[0] != len(bxpstats)): raise ValueError( "'usermedians' and 'x' have different lengths") else: # reassign medians as necessary for stats, med in zip(bxpstats, usermedians): https://github.com/cython/cython/blob/master/Cython/Tempita/_tempita.py#L270 if len(vars) != len(item): raise ValueError( 'Need %i items to unpack (got %i items)' % (len(vars), len(item))) for name, value in zip(vars, item): https://github.com/cython/cython/blob/master/Cython/Compiler/ExprNodes.py#L3... if len(specific_types) > len(fused_types): return error(self.pos, "Too many types specified") elif len(specific_types) < len(fused_types): t = fused_types[len(specific_types)] return error(self.pos, "Not enough types specified to specialize " "the function, %s is still fused" % t) # See if our index types form valid specializations for pos, specific_type, fused_type in zip(positions, specific_types,