2013-01-17 13 views
16

Quindi voglio fare qualcosa di simile:Tornando un'iterazione in un ciclo for

for i in range(5): 
    print(i); 
    if(condition==true): 
     i=i-1; 

Tuttavia, per qualsiasi motivo, anche se sto decrementare i, il ciclo non sembra accorgersene. C'è un modo per ripetere un'iterazione?

+3

non cambiare le ruote dell'auto quando ci si muove. –

+1

Di seguito sono riportate molte risposte che spiegano esattamente come incrementare 'i' in questo modo. Mi piacerebbe capire cosa stai facendo con 'i' in quanto potrebbe esserci un modo molto più chiaro di gestire questo codice. – Johnsyweb

risposta

20

for I loop in Python vanno sempre avanti. Se si vuole essere in grado di tornare indietro, è necessario utilizzare un meccanismo diverso, come ad esempio while:

i = 0 
while i < 5: 
    print(i) 
    if condition: 
     i=i-1 
    i += 1 

O ancora meglio:

i = 0 
while i < 5: 
    print(i) 
    if condition: 
     do_something() 
     # don't increment here, so we stay on the same value for i 
    else: 
     # only increment in the case where we're not "moving backwards" 
     i += 1 
+2

+1 per il refactoring più chiaro – wim

3

Hai un malinteso sui loop in Python. Il ciclo for non si preoccupa di ciò che si fa con i ad ogni iterazione, perché non è affatto correlato alla logica del ciclo. La modifica di i riassocia semplicemente una variabile locale.

Lei avrebbe bisogno di utilizzare un ciclo while per ottenere il comportamento che stai aspettando, qualora lo stato degli i influisce sul flusso di controllo del ciclo:

import random 

i = 0 
while i < 5: 
    print(i) 
    i += 1 
    if random.choice([True, False]): 
     i -= 1 
6

Python ciclo usando range sono di-design essere diverso da C/C++/Java for -loops. Per ogni iterazione, i viene impostato il valore successivo di range(5), indipendentemente da ciò che si fa a i in mezzo.

si potrebbe usare un ciclo while invece:

i = 0 
while i<5: 
    print i 
    if condition: 
     continue 
    i+=1 

Ma onestamente: Mi piacerebbe un passo indietro e ripensare il problema originale. Probabilmente troverai una soluzione migliore in quanto tali loop sono sempre soggetti a errori. C'è un motivo per cui Python for -loops è stato progettato per essere diverso.

2

utilizzano un ciclo while:

i = 0 
while i < 5: 
    print(i) 
    if condition: 
     i -= 1 
    i += 1 

Come si è detto, questo è piuttosto Python unidiomatic. Forse se pubblichi ciò che stai cercando di ottenere possiamo dare qualche consiglio migliore.

+0

Cosa succede a 'i' se la condizione è sempre vera? – Gabe

+1

Sei in un ciclo infinito –

2

range(5) crea un elenco con i numeri 0 attraverso 4 in esso - [0, 1, 2, 3, 4].

Quando si esegue un ciclo for su di esso, si sta iterando l'elenco. L'operazione i-= 1 decrementerà solo il valore di quel particolare elemento dell'elenco e l'iterazione continuerà.

Come suggerito dalle altre risposte, è necessario utilizzare un ciclo while.

i= 0 
while i<5: 
    # do stuff 
    if #condition: 
     i-= 1 # or + 
    i+= 1 
2

Ripetendo molte altre risposte, e solo per completezza, è necessario utilizzare un while loop.

i = 0 
while i < 5: 
    print(i) 
    if (not condition): 
     i+=1 

Se si desidera spostare indietro un'iterazione nel ciclo (invece di ripetere un'iterazione), quindi utilizzare questo:

i = 0 
while i < 5: 
    print(i) 
    if (condition): 
     i -= 1 
    else: 
     i += 1 

In sostanza, while i < 5 valuta il momento ogni iterazione, e controlla se i < 5. Così, con decremento/non cambiare i, otteniamo qualcosa di simile: (valori di i)

non cambiare: 1->2->3-(condition satisfied)> 3 -> 4 -> 5

Decrementale: 1->2->3-(condition satisfied)>2 -> 3 -> 4 -> 5

Il motivo per cui i=i-1 nel ciclo for non fa ripete l'iterazione è semplice. Nel ciclo for, i viene assegnato il valore dell'elemento successivo nel ciclo for. Python potrebbe interessarsi di meno di ciò che si fa con i, a condizione che sia in grado di assegnargli l'elemento successivo. Così, il ciclo for for i in <your_iterable>:<do whatever> è più vicino a questo:

_i = 0 
_length = len(<your_iterable>) 
while _i < _length: 
    i = _i 
    _i += 1 
    <do whatever> 

Tuttavia, in questa analogia, si sarebbe non essere in grado di accedere alle variabili _ predicate (_i, _length). Ecco come semplificare la logica di for loop. Si noti che indipendentemente da ciò che è assegnato a i, verrà assegnato a _i alla successiva iterazione e il ciclo non si preoccupa veramente di cosa sia i.

1

In Python è possibile impostare uno scambio bidirezionale tra un iteratore (quello che viene dopo in in un ciclo for..in) e il suo consumatore (codice all'interno del ciclo). Per ottenere ciò, è possibile utilizzare send nel codice utente per "iniettare" un valore in un generatore. Nel tuo caso, puoi semplicemente rispedire il valore corrente una volta che la condizione è soddisfatta e avvolgere la chiamata range in un generatore che ripete ciò che gli viene inviato. Ecco un codice per giocare, intenzionalmente dettagliato per chiarezza:

def repeateble(it): 
    buf, it = None, iter(it) 
    while True: 
     if buf is None: 
      # the buffer is empty, send them the next elem 
      val = next(it) 
     else: 
      # there's something in the buffer 
      # let's send that back 
      val = buf 

     # send the value and wait what they say 
     back = yield val 

     if back: 
      # they've sent us something! 
      # give them some dummy value as a result of send() 
      yield None 
      # and save what they've sent in a buffer 
      # for the next iteration 
      buf = back 

     else: 
      # they haven't sent anything 
      # empty the buffer 
      buf = None 


from random import randint 

# create a repeateble generator 
rng = repeateble(range(100)) 

for x in rng: 
    print(x) 

    # check "some condition"... 
    if randint(1, 100) > 80: 
     print('repeat:') 
     # send the current value back to the generator 
     # it will be returned on the next iteration 
     rng.send(x)