Christopher Barker writes:
But last time, one of the use cases was "get [an arbitrary] item from a dict", and there really is not a terribly easy (and efficient) way to do that now.
What's wrong with thedict.popitem()? Works in Python 2.7, BTW.
Granted, this doesn't help for a random item (and it's last, not first), but I think dicts are a pretty special case. The fact that they're ubiquitous and ordered in Python 3 makes "indexing into dicts" a real problem to be solved, but not by itertools.first, IMO.
OTOH, getting an arbitrary element, or state-dependent first element, from an iterable *is* simple, easy, *and obvious* to beginners: index with  if it's a sequence, and apply next() if it's an iterator. How many builtin or stdlib types are iterable, but neither sequences nor iterators? Builtin open(), zip(), reversed(), and enumerate(), for example, return iterators. Not to mention that only in the case of open() are they likely to have the iterator bound to an identifier they can apply itertools.first to.
So it's a good teaching moment, but not a great example of how Python usually has an easy and obvious way to do seemingly simple operations.
Polymorphic functions are not simple, almost by definition. IMHO, next(iter()) *is* Python giving us an easy and Zen-obvious way to do a polymorphic operation. It makes the following caveats Zen-obvious: it's state-dependent and destructive on iterators.