Come posso ottenere Python generatore di ritorno Nessuno piuttosto che StopIteration?

Sto usando generatori di effettuare ricerche negli elenchi come questo semplice esempio:

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

(Solo per inquadrare l’esempio un po’, sto usando molto di più liste rispetto a quella precedente, e le voci sono un po ‘ più complicato di int. Io lo faccio in questo modo l’intera lista non può essere calpestato ogni volta che cerco di loro)

Ora, se io, invece, un cambiamento che per i == 666, avrebbe restituito una StopIteration perché non in grado di trovare qualsiasi 666 entrata in a.

Come posso farlo tornare None invece? Potrei, naturalmente, avvolgerla in un try ... except clausola, ma c’è un di più divinatori modo per farlo?

  • Posso chiedere perché si sta utilizzando generatori di cercare le cose?
  • Cosa potrebbe accadere se si cerca qualcosa si sia già passato oltre? Perché non usare semplicemente il piu ‘divinatori’ come if i in a: ...?
  • D, if i in a non aiuta se si desidera ottenere l’indice dell’elemento trovato.
  • Si potrebbe utilizzare a.index(i). Non ha la delicatezza di utilizzare enumerate, è vero, ma mi sto appassionando a cui non si voglia utilizzare un generatore di ricerca in una lista.
  • D, è vero, ma solo per iterables con un definito index metodo. Inoltre, se si desidera provare un qualcosa di diverso dalla semplice uguaglianza-per esempio, se si desidera trovare il primo elemento che > 5 — quindi index non aiuta. Comunque, hai ragione che l’esempio specifico c00kiemonster ha dato, index è l’approccio più razionale.
  • Come ho detto in un commento qui sotto, l’elenco effettivo elementi sono gli oggetti e i confronti coinvolgere attributi in modo che io non so davvero come calzascarpe in la if i in a idioma
  • Hm, che è un buon esempio, non penso che. Un generatore sembrerebbe meglio in questo caso. @c00kiemonster: credo che si può definire il __iter__ proprietà della classe per essere in grado di utilizzare il if i in a idioma.
  • D, non è una cattiva idea. grazie per il suggerimento

 

2 Replies
  1. 117

    Se si utilizza Python 2.6+ si dovrebbe usare il avanti funzione built-in, non next metodo (che è stato sostituito con __next__ in 3.x). Il next built-in opzionale argomento di default per tornare se l’iteratore è esaurito, invece di elevare StopIteration:

    next((i for i, v in enumerate(a) if i == 666), None)
    • Non sapevo che il built-in funzione era cambiato. Che rende molto più semplice per assicurarsi
    • La ringrazio per la risposta. Ma io sto usando Python 3.6.3 che sta lavorando per il mio progetto.
  2. 7

    È possibile collegare il generatore in (None):

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

    ma penso che una.indice(2) non attraversare l’elenco completo, quando 2 si trova, la ricerca è terminata. puoi provare questo:

    >>> timeit.timeit("a.index(0)", "a=range(10)")
    0.19335955439601094
    >>> timeit.timeit("a.index(99)", "a=range(100)")
    2.1938486138533335
    • La catena di cosa è stata molto intelligente, non penso che uno. Sì index() non è male, ma nel mio caso reale non so veramente utilizzarlo come le voci dell’elenco sono oggetti piuttosto che variabili. EDIT: sto confrontando gli attributi di un oggetto e altre cose divertenti, piuttosto che alla ricerca per l’oggetto stesso.
    • Dispiace dirlo, ma questa è una soluzione complicata. Il next built-in funzione già offre questa funzionalità in modo pulito. @c00kiemonster, penso che si dovrebbe usare (e accettare) zeekay la risposta.
    • Nessun problema, un buon modo per capire il più recente roba in Python, se non altro…

Lascia un commento