web-dev-qa-db-fra.com

Comment puis-je obtenir un générateur Python pour retourner None plutôt que StopIteration?

J'utilise des générateurs pour effectuer des recherches dans des listes comme cet exemple simple:

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

(Juste pour encadrer un peu l'exemple, j'utilise des listes beaucoup plus longues par rapport à celle ci-dessus, et les entrées sont un peu plus compliquées que int. Je le fais de cette façon pour que toutes les listes gagnent ' t être parcouru chaque fois que je les recherche)

Maintenant, si je le changeais plutôt en i == 666, il retournerait un StopIteration car il ne peut pas trouver de 666 entrée dans a.

Comment puis-je le faire retourner None à la place? Je pourrais bien sûr l'envelopper dans un try ... except clause, mais existe-t-il une manière plus pythonique de le faire?

47
c00kiemonster

Si vous utilisez Python 2.6+, vous devez utiliser la fonction intégrée next , pas la méthode next (qui était remplacé par __next__ en 3.x). Le next intégré prend un argument par défaut facultatif à renvoyer si l'itérateur est épuisé, au lieu d'augmenter StopIteration:

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

Vous pouvez chaîner le générateur avec (Aucun,):

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

mais je pense que a.index (2) ne traversera pas la liste complète, lorsque 2 est trouvé, la recherche est terminée. vous pouvez tester ceci:

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