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?