Как я могу заставить генератор Python возвращать None, а не StopIteration? - PullRequest
38 голосов
/ 18 августа 2011

Я использую генераторы для выполнения поиска в списках, как в этом простом примере:

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

(Просто для небольшого кадрирования примера я использую очень длинные списки по сравнению с приведенным выше изаписи немного сложнее, чем int. Я делаю это таким образом, чтобы при каждом поиске не просматривались полные списки)

Теперь, если я вместо этого изменим это на i == 666,он вернул бы StopIteration, потому что не может найти запись 666 в a.

Как я могу вместо этого вернуть None?Я мог бы, конечно, обернуть это в try ... except предложение, но есть ли более питонический способ сделать это?

Ответы [ 2 ]

107 голосов
/ 18 августа 2011

Если вы используете Python 2.6+, вам следует использовать встроенную функцию next, а не метод next (который был заменен на __next__ в 3.x). Встроенный next принимает необязательный аргумент по умолчанию, возвращаемый, если итератор исчерпан, вместо вызова StopIteration:

next((i for i, v in enumerate(a) if i == 666), None)
7 голосов
/ 18 августа 2011

Вы можете связать генератор с помощью (Нет,):

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

но я думаю, что a.index (2) не будет проходить по всему списку, когда 2 найдено, поиск завершен Вы можете проверить это:

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