[Steven D'Aprano] ...
I don't recall who wants a version of first that raises,
I do, for one. But I want both (raising and non-raising) behaviors at times, and the more-itertools version supplies both.
or when that would be useful.
There is no practical way to assert than an iterable isn't exhausted. In most of my algorithms, I "know" that first's argument is not empty or exhausted, and it's a logic error if they are. So I want an attempt to retrieve something that doesn't exist to raise. Stuff like: _empty = object() a = first(it, _empty) if a is _empty: raise ValueError(...) is a PITA. I can't generally _assume_, e.g., that None is a magical value in this context.
It would greatly limit it's usefulness in expressions, since it needs to be guarded by a try...except.
The non-raising version is obtained by explicitly passing a default to return in case the iterable is empty/exhausted. [from a different reply]
py> {1:'a'}.get(999) is None True
As Guido said before he tuned out, it's the _sole purpose_ of dict.get(key) not to raise, so there's no reason to require an explicit default in that context. If you want a spelling that does raise, fine,,, dict[key] - or dict.__getitem__(key) is what you want. The more-itertools first() works not like dict.get(), but dict.pop(): raise an exception in the endcase by default, but that can be overridden by explicitly passing a value to return in that case. And for the same reason: raising and non-raising versions are both desirable,