
On Fri, May 15, 2020 at 08:17:12AM +0100, Paul Moore wrote:
1. Why do we want to "tempt" people to error when handling mismatched lengths? Certainly letting people catch errors easily is worthwhile, but rejecting arguments of different lengths may well *not* be an error ("be lenient in what you accept" is a well-known principle, even if not something that everyone agrees on in all cases).
I concur with Paul here. There may be cases where mismatched lengths are an error, but there are also cases where they are not an error. It is patronising to be talking about tempting people into using the strict version of zip. People who need it will find it, whether it is builtin or not.
2. I find "mode switch" arguments ugly
I think we need to distinguish between *modes* and *flags*. This proposed functionality is a mode, not a flag. Mode switches are extensible: zip(*args, mode='strict') can easily be extended in the future to support new modes, such as zip_longest. There are at least two other modes that have been mentioned briefly in the Python-Ideas thread: 1. a variety of zip that returns information in the StopIterator exception identifying the argument that was empty and those that weren't; 2. a variety of zip that simply skips the missing arguments: zip_skip('abc', 'ef', 'g') => (a, e, g) (b, f), (c,) I don't even understand the point of the first one, or how it would operate in practice, or why anyone would need it, but at least one person thinks it would be useful. Take that as you will. But I have written my own version of the second one, and used it. A mode parameter naturally implies that only one mode can apply at a time, and it naturally enforces that restriction without any additional programmer effort. If there are (let's say...) four different modes: mode = shortest|longest|strict|skip you can only supply one at a time. Using *named modes* (whether as strings or enums) to switch modes is quite reasonable. It's not my preferred API for this, but I don't hate it. But a *flag* parameter is difficult to extend without making both the API and the implementation complicated, since any extension will use multiple parameters: zip(*args, strict=True, longest=False, skip=True) and the caller can supply any combination, each of which has to be tested for, exceptions raised for the incompatible combinations. With three flags, there are eight such combinations, but only four valid ones. With four flags, there are 16 combinations and only five meaningful combinations. Flags work tolerably well when the parameters are independent and orthogonal, so you can ask for any combination of flags. But flags to switch modes are *not* independent and orthogonal. We can't combine them in arbitrary combinations. Using *boolean flags* to switch modes in this way makes for a poor API. For the record, my preferred APIs for this are in order: 1. +1 itertools.zip_strict function 2. +1 zip.strict(*args) 3. +1 zip(*args, mode='strict') # mode='shortest' by default 4. +0 zip(*args, strict=True) and even that is being generous for option 4. Note that options 1 and 2 have an important advantage over options 3 and 4: the strict version of zip is a first-class callable object that can be directly passed around and used indirectly in a functional way. E.g. for testing using unittest: assertRaises(zip.strict, 'a', '', Exception) Yes, assertRaises is also usable as a context manager, but this is just an illustration of the functional style. -- Steven