2011-08-18 7 views
27

estoy utilizando generadores para realizar búsquedas en las listas como este sencillo ejemplo:¿Cómo puedo obtener un generador de Python para que devuelva None en lugar de StopIteration?

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

(Sólo para enmarcar un poco el ejemplo, estoy usando listas mucho más largos en comparación con la de arriba, y las entradas son una poco más complicado que int. lo hago de esta manera por lo que las listas completas no serán atravesados ​​cada vez que me los busco)

Ahora si me gustaría cambiar eso en lugar de i == 666, devolvería un StopIteration ya que puede' t encuentra cualquier entrada 666 en a.

¿Cómo puedo hacer que vuelva None en su lugar? Por supuesto, podría envolverlo en una cláusula try ... except, pero ¿hay una forma más pitonica de hacerlo?

+0

¿Puedo preguntar por qué estás utilizando generadores para buscar cosas? –

+0

¿Qué esperas que pase si buscas algo que ya pasaste por alto? ¿Por qué no usar la forma más "pitonica" como 'si yo en a: ...'? –

+0

@Manny D, 'if i in a' no ayuda si desea obtener el índice del elemento encontrado. – senderle

Respuesta

70

Si está utilizando Python 2.6+ debe utilizar el next función incorporada, no es el método next (que fue reemplazado por __next__ en 3.x). El next incorporada toma un argumento opcional default volver si se agota el iterador, en lugar de elevar StopIteration:

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

+1, esta es la mejor manera de hacerlo. – senderle

+0

No sabía que la función incorporada había cambiado. Eso hace que sea mucho más fácil seguro – c00kiemonster

7

se pueden encadenar con el generador (Ninguna,):

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

pero creo a.index (2) no va a recorrer la lista completa, cuando se encuentra 2, la búsqueda ha terminado. puede probar esto:

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

La cosa de la cadena fue muy inteligente, no pensé en eso. Sí 'index()' no está mal, pero en mi caso real no puedo usarlo ya que las entradas de la lista son objetos en lugar de variables. EDITAR: estoy comparando atributos de objetos y otras cosas divertidas en lugar de solo buscar el objeto en sí. – c00kiemonster

+1

Lamento decir esto, pero esta es una solución demasiado complicada. La función incorporada 'next' ya ofrece esta funcionalidad de una manera limpia. @ c00kiemonster, creo que deberías usar (y aceptar) [la respuesta de Zeekay] (http://stackoverflow.com/questions/7102050/how-can-i-get-a-python-generator-to-return-none-rather -than-stopiteration/7102204 # 7102204). – senderle

+0

Sin preocupaciones, una buena forma de descubrir las cosas más nuevas en Python si nada más ... – c00kiemonster

Cuestiones relacionadas