There's a simple function that I use many times, and I think may be a good fit to be added to itertools. A function that gets an iterator, and if it has exactly one element returns it, and otherwise raises an exception. This is very useful for cases where I do some sort of query that I expect to get exactly one result, and I want an exception to be raised if I'm wrong. For example:
jack = one(p for p in people if p.id == '1234')
sqlalchemy already has such a function for queries: https://docs.sqlalchemy.org/en/13/orm/query.html#sqlalchemy.orm.query.Query....
more-itertools has this exact function: https://more-itertools.readthedocs.io/en/latest/api.html#more_itertools.one
Here is a simple implementation:
def one(iterable): it = iter(iterable) try: first = next(it) except StopIteration: raise ValueError("Iterator is empty") try: second = next(it) except StopIteration: return first else: raise ValueError("Iterator has more than one item")
I brought this up on python-dev, but it should be discussed here. Here is the discussion: https://email@example.com/thread/D52MPKLIN...
Brett Cannon said that this idea has been brought up at least twice before. I found: https://firstname.lastname@example.org/thread/FTJ6JRD...
The first thread hasn't reached any operative conclusion. The second thread was very long, and seemed to focus mostly on another function, first(), that doesn't check if there is more than one item. Joao S. O Bueno said that it passed "general approval". I think that perhaps a new discussion, focused just on one (no pun intended) function in the itertools module may reach a conclusion.
It was suggested that instead of an additional function, one can use iterator unpacking:
jack, = (p for p in people if p.id == '1234') or [jack] = (p for p in people if p.id == '1234')
I still think that having a one() function would be useful, since: 1. I think it spells the intention more clearly. It is not symbols that you need to understand their meaning in order to understand that I expect the iterable to have exactly one item, it's spelled in code. 2. The exception would be easier to understand, since errors in tuple unpacking usually mean something else. 3. The one() function allows you to use the result inside an expression without assigning it to a variable. Therefore, I think it encourages writing better code. It's very easy to write: print([p for p in people if p.id == '1234]) (which has the problem of not verifying the assumption that there's no more than one result), and I find it easier to replace _ with one(_) than to be required to name a new variable, and instead of having an operation on the iterable, change the way I'm assigning to it.