I think a solution nobody has proposed in this thread is relaxing the next builtin, so it calls iter() on the argument when it doesn't implement the iterator protocol. That would make next([1, 2]) == 1, and also make next([], "missing") == "missing". After that all that is needed is educating the users a bit about the 2-argument form of next (which after this thread, sounds like a good idea by itself anyway).

I don't think the performance impact should be big (it would add a check and a method call but only on a path that currently raises a TypeError, which shouldn't be typically in a hot path).

Compatibility-wise, it potentially turns TypeError raising code into non-raising code, which might make a difference if someone is catching this and doing something special with it, but IMHO I don't think that's something that should happen a lot (and is the kind of backward incompatible changes that are tolerated between releases.

Do you see any drawbacks I missed? Do you think this fails to cover the original problems in any way?

On Wed, 11 Dec 2019 at 01:22, Tim Peters <tim.peters@gmail.com> wrote:
[Tim]
>> For me, most of the time, it's to have an obvious, uniform way to
>> spell "non-destructively pick an object from a container (set, dict,
>> list, deque, heap, tuple, custom tree class, ...)".  I don't even have
>> iterators in mind then, except as an implementation detail.

[Steven]
> You can't *non-destructively* pick the first (or next, or any) element
> of an iterator.

Obviously.  That's why I wrote "container", and then gave 7 concrete
examples in case that distinction was too subtle ;-)

But do note my "most of the time" too.  There are also uses for
iterators, but for _me_ those are not most common.  For others they
may be.

> ...
> It sounds to me that what you actually want is an analogue to
> Mapping.get that applies to all containers and sequences and leaves
> iterators completely out of it.

No, I want `first()`.  It solves more than one problem.  For iterators
I nearly always use plain `next(iterator)`, but there are (for _me_,
rare) cases where I'd like to do, e.g., `first(iterator, sentinel)`
instead.

I'm not at all bothered that for some arguments `first()` mutates
state and for others it doesn't, no more than I'm bothered that `for x
in iterable:` may or may not "consume" the iterable.

> ...
> I could completely get behind this idea! The only tricky part is the
> "index" isn't well-defined for mappings and sets, or tree-like
> containers.

While the meaning of `first()` is clear for any iterable argument.
_______________________________________________
Python-ideas mailing list -- python-ideas@python.org
To unsubscribe send an email to python-ideas-leave@python.org
https://mail.python.org/mailman3/lists/python-ideas.python.org/
Message archived at https://mail.python.org/archives/list/python-ideas@python.org/message/PRMVKU2JLZBOBSNAMP2Q7HKMDH7RLKPR/
Code of Conduct: http://python.org/psf/codeofconduct/