
On Mon, Dec 09, 2019 at 10:19:43PM -0400, Juancarlo Añez wrote:
And knowing that you must use *iter()* for 2-arg *next()* to (maybe) work right is idiosyncratic.
If you think that knowing to use `iter` before calling `next` is somehow advanced or difficult knowledge, I think that you have an exaggerated idea of the ineptitude of the average Python programmer. Anyone who calls `next` directly on a list or other non-iterator will get a TypeError: TypeError: 'list' object is not an iterator which makes it pretty obvious that the solution is to call `iter` first. I know absolute beginners won't read error messages, but that's a skill that people learn pretty quickly.
It takes a "Python historian" to understand why it *may be correct* to use:
the_first_item_if_ordered = next(iter(container), default='not found')
What do you mean by "may be correct"? Can you give an example of when it isn't correct, assuming `container` is an iterable?
While the semantics of *first()* (whichever the chosen implementation) are straightforward to explain:
one_item_if_any = first(return_a_set(), default=-1)
I don't think it's more straightforward than the `next` version. There are at least two gotchas, or possibly two sides of the same gotcha, one minor and one (in my opinion) major. The first is that, in a sense, the name `first` is misleading: it doesn't return the *first* item from an iterator, since the first item may be long gone; it returns the *next* item of an iterator. If I have `letters = iter("abcde...z")` and have already advanced into the middle of the iterator, a naive user might expect that first(letters) will return "a" rather than whatever the next letter happens to be. But the more serious gotcha is that `first` behaves very differently when called repeatedly on an iterator compared to other iterables.
I agree with others in that the "*default*" argument should be explicit instead of implied. It's how *dict.get()*, and *dict.pop()*, etc., work.
When you say "explicit instead of implied", do you mean that there is no default value for the default? If so, that's not how dict.get works: py> {}.get('some key') is None True -- Steven