
On Tue, Dec 10, 2019 at 09:47:08PM -0500, Kyle Stanley wrote:
I think itertools.first() is a good example of something that would be useful and general-purpose enough to be included as a function in itertools.
And I think that this discussion demonstrates why it is so hard to decide which recipes are promoted to full functions. Apologies to Raymond in advance if I fail to channel him correctly, but I think his argument will be that this discussion shows why people ought to implement their own `first` if they need it: - should it raise on an empty iterable or return a default value? - if we should raise, what should we raise? - if the caller doesn't provide a default, should it raise or return a default default, like None? - should it work on non-iterators? if yes, the behaviour between iterators and non-iterators is subtly different and a potential bug magnet for anyone who calls `first` twice on the same argument
If even those who have been involved with Python's development since its infancy aren't overly familiar with 2-arg next(), how could we reasonably expect the average user to be?
I think we're reading too much into Guido's momentary lapse of memory or slight lack of knowledge, whichever the case may be. Nobody can be expected to know *everything*, not even Guido, and we're all entitled to miss the odd thing here or there. But having said that, `next` is a builtin, not some obscure corner of some little-used library. Python has a wonderfully effective interactive interpreter where documentation for `next` is one command away: py> help(next) Help on built-in function next in module builtins: next(...) next(iterator[, default]) Return the next item from the iterator. If default is given and the iterator is exhausted, it is returned instead of raising StopIteration. If you google for `next`, the very first result mentions the default right there on the search page, no need to click through: https://duckduckgo.com/?q=python+next (Your mileage may vary when using other search engines.) In addition, the very first post in this thread suggested using the two-argument form of `next` in their implemention. And there's no `first` recipe, which suggests that Raymond thought it was too obvious to bother with. (I'm kinda-sorta in agreement with that, but maybe this thread shows different.) I'm not saying that it is an unforgivable failure for a developer to not know about the 2-arg form of next, that would be ludicrous. But it's not unreasonable to expect developers to use the 2-arg form of `next`. The suggested `first` is just a simple composition of two well-known builtins; saying that nobody can be expected to know the 2-arg form, or be able to plug the pieces together, is unconvincing. I'm really on the fence with this one. Comparing the two: next(iter(obj), default) itertools.first(obj, default) I can easily see myself preferring the first as obvious and explicit and easier than having to import a module. But if I had already imported the module for other functions, I might prefer the second. Same reason I will often just write `x**(1/2)` or `pow(x, 0.5)` rather than `import math; math.sqrt(x)` unless I've already needed the math module for something else. -- Steven