
On Mon, Jun 01, 2020 at 09:36:40PM +1000, Nick Coghlan wrote:
zip() can be used to combine iterables of different lengths, including combining finite iterables with infinite iterators. By default, the output iterator is implicitly truncated to produce the same number of items as the shortest input iterable. Setting *truncate* to false disables this implicit truncation and raises ValueError instead.
It's not really *implicit* if there's an explicit flag controlling the behaviour, even with a default value. We don't use that sort of language elsewhere. For example, help(sorted) doesn't say: "Return a new list containing all items from the iterable implicitly in ascending order. Pass reverse=True to disable this implicit order." help(int) doesn't say that the base is implicitly decimal; help(print) doesn't talk about "implicit spaces between items, implicit newline at the end of the output" etc. It just states the behaviour controlled by the parameter. This is accurate, non-judgemental, and avoids being over-wordy: "By default, the output iterator is truncated at the shortest input iterable."
The conceptual idea here is that the "truncate" flag name would technically be a shorter mnemonic for "truncate_silently", so clearing it gives you an exception rather enabling padding behaviour.
Flipping the sense of the flag also means that "truncate=True" will appear in IDE tooltips as part of the function signature, providing significantly more information than "strict=False" would.
"Significantly" more? I don't think so. Truncate at what? - some maximum length; - some specific element; - at the shortest input. At some point people have to read the docs, not just the tooltips. If you didn't know what zip does, seeing truncate=True won't mean anything to you. If you do know what zip does, then the parameter names are mnemonics, and strict=False and truncate=True provide an equal hint for the default behaviour: * if it's not strict, it is tolerant, stopping at the shortest; * if it truncates, it truncates at the shortest input. For the default case, strict=False and truncate=True are pretty much equal in information. But for the case of non-default behaviour, strict=True is a clear winner. It can pretty much only mean one thing: raise an exception. Whereas truncate=False is ambiguous: - pad the output; - skip items as they become empty; - raise an exception. All three of these are useful behaviour, and while the middle one is not part of this PEP, it was requested in the discussions on Python-Ideas.
That improved self-documentation then becomes what I would consider the strongest argument in favour of the flag-based approach:
I don't think that "truncate=False" (which can mean three different things) is more self-documenting than `zip(*items, mode='strict')` or `zip_strict()` (either of which can only mean one thing). -- Steven