I created a utility function to return the expected single item from an generator expression
print one(name for name in ('bob','fred') if name=='bob')
Is this a good way to go about it?
def one(g):
try:
val = g.next()
try:
g.next()
except StopIteration:
return val
else:
raise Exception('Too many values')
except StopIteration:
raise Exception('No values')
A simpler solution is to use tuple unpacking. This will already do everything you want, including checking that it contains exactly one item.
Single item:
>>> name, = (name for name in ('bob','fred') if name=='bob')
>>> name
'bob'
Too many items:
>>> name, = (name for name in ('bob','bob') if name=='bob')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: too many values to unpack
No items:
>>> name, = (name for name in ('fred','joe') if name=='bob')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: need more than 0 values to unpack
For those using or interested in a third-party library, more_itertools
implements such a tool with native error handling:
> pip install more_itertools
Code
import more_itertools as mit
mit.one(name for name in ("bob", "fred") if name == "bob")
# 'bob'
mit.one(name for name in ("bob", "fred", "bob") if name == "bob")
# ValueError: ...
mit.one(name for name in () if name == "bob")
# ValueError: ...
See more_itertools
docs for details. The underlying source code is similar to the accepted answer.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With