How can I get a Python generator to return None rather than StopIteration?

I am using generators to perform searches in lists like this simple example:

>>> a = [1,2,3,4]
>>> (i for i, v in enumerate(a) if v == 4).next()
3

(Just to frame the example a bit, I am using very much longer lists compared to the one above, and the entries are a little bit more complicated than int. I do it this way so the entire lists won't be traversed each time I search them)

Now if I would instead change that to i == 666, it would return a StopIteration because it can't find any 666 entry in a.

How can I make it return None instead? I could of course wrap it in a try ... except clause, but is there a more pythonic way to do it?


Solution 1:

If you are using Python 2.6+ you should use the next built-in function, not the next method (which was replaced with __next__ in 3.x). The next built-in takes an optional default argument to return if the iterator is exhausted, instead of raising StopIteration:

next((i for i, v in enumerate(a) if i == 666), None)

Solution 2:

You can chain the generator with (None,):

from itertools import chain
a = [1,2,3,4]
print chain((i for i, v in enumerate(a) if v == 6), (None,)).next()

but I think a.index(2) will not traverse the full list, when 2 is found, the search is finished. you can test this:

>>> timeit.timeit("a.index(0)", "a=range(10)")
0.19335955439601094
>>> timeit.timeit("a.index(99)", "a=range(100)")
2.1938486138533335