Python iterators, as well as supporting next(), have a return value. This is fiendishly difficult to access in any clean way; maybe it would be used more if that situation were improved?
Thinking about this, I realised there’s a solution that to me feels very simple, clean, Pythonic and potentially painless to implement:
In the same way that try statements have an except clause that supports except TYPE as VAR:, why not allow else VAR: in for statements as well as just else, the result of the iteration being assigned to VAR.
So:
for item in my_iterable:
process_item(item)
else result:
process_result(result)
This has the pleasing benefit that the else clause is already executed in exactly the circumstance that the iterator has run to completion and returned a value.
I guess so. I did try searching for previous suggestions before submitting mine, but that one somehow eluded me.
I do feel my else result: suggestion is more literate than else as result:. I also feel that augmenting for…else offers a couple of significant advantages over the various workarounds:
It makes writing correct code very natural and incorrect code impossible: the workarounds tend to end up providing something tantamount to a future/promise that might get called prematurely (or down an exception path, or having abandoned the iterator before exhausting it).
It can give better performance if implemented in the interpreter. (timeit reveals that allowing StopIteration to be raised and caught is especially punitive)
I do see the argument that return values from iterators are a relic rather than a feature intended to be used, but I’ve found myself wanting to use them relatively often. Most recently, I was writing a function that returned the top n values from an iterator, but which also wanted to yield a running commentary, noting each time a larger value evicted an existing one. Another was wanting to pass an iterator through while also returning the “size” (by some definition) of all values.
If this isn’t going to happen, a less elegant but also useful option might be an iterator tool that takes an iterator and yields a series of (True,yielded_value) tuples followed by a (False,returned_value) tuple?