Elenco Python comportamento dell'iteratore e successivo (iteratore)


147

Tener conto di:

>>> lst = iter([1,2,3])
>>> next(lst)
1
>>> next(lst)
2

Quindi, l'avanzamento dell'iteratore viene, come previsto, gestito mutando lo stesso oggetto.

Stando così le cose, mi aspetterei:

a = iter(list(range(10)))
for i in a:
   print(i)
   next(a)

per saltare ogni secondo elemento: la chiamata a nextdovrebbe far avanzare l'iteratore una volta, quindi la chiamata implicita fatta dal loop dovrebbe avanzare una seconda volta - e il risultato di questa seconda chiamata verrebbe assegnato i.

Non Il ciclo stampa tutti gli elementi nell'elenco, senza saltarne nessuno.

Il mio primo pensiero è stato che ciò potrebbe accadere perché il loop chiama iterciò che viene passato e questo potrebbe dare un iteratore indipendente - non è così, come abbiamo fatto iter(a) is a.

Quindi, perché nextnon sembra avanzare l'iteratore in questo caso?

Risposte:


197

Quello che vedi è l' interprete che fa eco al valore di ritorno next()oltre a iessere stampato ogni iterazione:

>>> a = iter(list(range(10)))
>>> for i in a:
...    print(i)
...    next(a)
... 
0
1
2
3
4
5
6
7
8
9

Così 0è l'output di print(i), 1il valore restituito da next(), riecheggiato dall'interprete interattivo, ecc. Ci sono solo 5 iterazioni, ciascuna iterazione che porta a 2 righe che vengono scritte sul terminale.

Se si assegna l'output delle next()cose funziona come previsto:

>>> a = iter(list(range(10)))
>>> for i in a:
...    print(i)
...    _ = next(a)
... 
0
2
4
6
8

o stampa informazioni aggiuntive per differenziare l' print()output dall'eco dell'interprete interattivo:

>>> a = iter(list(range(10)))
>>> for i in a:
...    print('Printing: {}'.format(i))
...    next(a)
... 
Printing: 0
1
Printing: 2
3
Printing: 4
5
Printing: 6
7
Printing: 8
9

In altre parole, next()funziona come previsto, ma poiché restituisce il valore successivo dall'iteratore, ripetuto dall'interprete interattivo, si è indotti a credere che il ciclo abbia in qualche modo la propria copia dell'iteratore.


13
Non ero a conoscenza di questo comportamento dall'interprete. Sono contento di averlo scoperto prima di perdere molto tempo a chiedermi mentre risolvo qualche problema reale.
brandizzi,

5
... *muore*. Il peggio è che ricordo di aver menzionato esattamente questo comportamento da interprete a qualcuno forse una settimana fa.
PVC

interessante. Ho provato per i in a: next (a); stampa i e ho pensato di saltare a 1 e stampare 1,3,5,7,9. Ma è ancora 0,2,4,6,8. Perché?
user2290820

3
iera già stato assegnato. next(a)significa che 2viene assegnata la successiva iterazione i, quindi ti sposti di anuovo, stampa i, ecc.
Martijn Pieters

1
Questo non funziona se n è dispari: StopIterationexcepetio n viene generato quando next(a)viene chiamato dopo che l'elenco è esaurito.
Raf

13

Ciò che sta accadendo è che next(a)restituisce il valore successivo di a, che viene stampato sulla console perché non è interessato.

Quello che puoi fare è influenzare una variabile con questo valore:

>>> a = iter(list(range(10)))
>>> for i in a:
...    print(i)
...    b=next(a)
...
0
2
4
6
8

8

Trovo le risposte esistenti un po 'confuse, perché indicano solo indirettamente la cosa mistificante essenziale nell'esempio di codice: sia * la "stampa i" che la "prossima (a)" stanno causando la stampa dei loro risultati.

Dal momento che stanno stampando elementi alternati della sequenza originale ed è inaspettato che l'istruzione "next (a)" stia stampando, sembra che l'istruzione "print i" stia stampando tutti i valori.

Alla luce di ciò, diventa più chiaro che l'assegnazione del risultato di "next (a)" a una variabile inibisce la stampa del suo 'risultato, cosicché vengono stampati solo i valori alternativi che la variabile del ciclo "i". Allo stesso modo, fare in modo che la frase "print" emetta qualcosa di più distintivo la chiarisce.

(Una delle risposte esistenti confuta le altre perché quella risposta sta facendo valutare il codice di esempio come un blocco, in modo che l'interprete non stia riportando i valori intermedi per "next (a)".)

La cosa seducente nel rispondere alle domande, in generale, è essere espliciti su ciò che è ovvio quando si conosce la risposta. Può essere sfuggente. Allo stesso modo criticare le risposte dopo averle capite. È interessante...


2

Qualcosa non va nel tuo Python / Computer.

a = iter(list(range(10)))
for i in a:
   print(i)
   next(a)

>>> 
0
2
4
6
8

Funziona come previsto.

Testato in Python 2.7 e in Python 3+. Funziona correttamente in entrambi


5
Ottengo lo stesso risultato di @lvc (solo su IDLE comunque, quando eseguito come script ottengo questo))
jamylak,

3
@Inbar Rose Solo se eseguito come script.
Quintec,

1
è il comportamento di mettere il codice tramite shell interattiva. Se la funzione restituisce valore senza essere utilizzata, l'interprete lo stampa sulla shell come output di debug
Reishin

2

Per coloro che ancora non capiscono.

>>> a = iter(list(range(10)))
>>> for i in a:
...    print(i)
...    next(a)
... 
0 # print(i) printed this
1 # next(a) printed this
2 # print(i) printed this
3 # next(a) printed this
4 # print(i) printed this
5 # next(a) printed this
6 # print(i) printed this
7 # next(a) printed this
8 # print(i) printed this
9 # next(a) printed this

Come altri hanno già detto, nextaumenta l'iteratore di 1 come previsto. L'assegnazione del valore restituito a una variabile non modifica magicamente il suo comportamento.


1

Si comporta nel modo desiderato se chiamato come funzione:

>>> def test():
...     a = iter(list(range(10)))
...     for i in a:
...         print(i)
...         next(a)
... 
>>> test()
0
2
4
6
8
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.