
On Tue, Dec 10, 2019 at 10:54:10AM +1300, Greg Ewing wrote:
Can you provide any insight into why you think it's better for it never to raise an exception, as opposed to raising something other than StopIteration when the iterator is empty and no default is specified?
Speaking for myself, not Guido, functions which raise are often difficult to use, especially if you can't "Look Before You Leap", since you have to wrap them in a try...except block to use them. Since we don't have an expression form to catch exceptions, you have to lift the possibly-may-fail call out of the expression. E.g. with strings you can write variants of: result = spam() if thestring.find(x) > 2 else eggs() versus something like this: try: idx = thestring.index(x) except IndexError: idx = -1 result = spam() if idx > 2 else eggs() which is much less convenient and much more boilerplatey.
Your version of the function seems to be aimed exclusively at case 1. If it were to raise ValueError on an empty iterable unless a default were explicitly given, it would address both cases.
You can always pass an impossible value and test for it. If your iterables are never None, pass None as the default. Or NotImplemented also makes a good sentinel. If either of those could be a legitimate value, make your own sentinel: NULL = object() result = first(iterable, NULL) if result is NULL: handle_error() -- Steven