Pitone: un'iterazione su una lista non vuota senza se clausola esce vuoto. Perché?
-
22-08-2019 - |
Domanda
Come può un iteratore su una sequenza non vuota, senza filtraggio e senza aggregazione (sum()
, ecc), resa nulla?
Si consideri un semplice esempio:
sequence = ['a', 'b', 'c']
list((el, ord(el)) for el in sequence)
Questo produce [('a', 97), ('b', 98), ('c', 99)]
come previsto.
Ora, basta scambiare la ord(el)
fuori per un'espressione che prende il primo valore di qualche generatore utilizzando (...).next()
- perdonare l'esempio inventato:
def odd_integers_up_to_length(str):
return (x for x in xrange(len(str)) if x%2==1)
list((el, odd_integers_up_to_length(el).next()) for el in sequence)
Questo produce []
. Sì, lista vuota. Nessun tuple ('a',
stuff)
. Niente.
Ma non stiamo filtrando o aggregazione o la riduzione. Un generatore di espressione sopra n
oggetti senza filtrazione o aggregazione deve cedere oggetti n
, giusto? Cosa sta succedendo?
Soluzione
odd_integers_up_to_length(el).next()
alzerà StopIteration, che non è catturato lì, ma viene catturato per il generatore di espressione all'interno di esso, fermandosi senza mai cedere nulla.
sguardo alla prima iterazione, quando il valore è 'a':
>>> odd_integers_up_to_length('a').next()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration
Altri suggerimenti
Succede che la chiamata next()
solleva un'eccezione StopIteration
che si propaga la pila all'espressione generatore esterno e ferma che iterazione.
Una StopIteration
è il modo normale per un iteratore per segnalare che il gioco è fatto. Generalmente non vediamo, perché in genere la chiamata next()
avviene all'interno di un costrutto che consuma l'iteratore, ad esempio for x in iterator
o sum(iterator)
. Ma quando chiamiamo direttamente next()
, noi siamo i responsabili per prendere il StopIteration
. Non farlo scaturisce una perdita nel astrazione, che qui porta a un comportamento imprevisto nell'iterazione esterno.
La lezione, suppongo: attenzione sulle chiamate senza scalo a next()
str è una parola chiave riservata, è necessario denominare la variabile in modo diverso
Sono stato anche di consigliare circa il prossimo
>>> seq=['a','b','c']
>>> list((el,4) for el in seq)
[('a',4), ('b',4), ('c',4)]
Quindi non è list
dando problemi qui ...