Reputation: 1052
So I want to do something like this:
for i in range(5):
print(i);
if(condition==true):
i=i-1;
However, for whatever reason, even though I'm decrementing i, the loop doesn't seem to notice. Is there any way to repeat an iteration?
Upvotes: 37
Views: 47231
Reputation: 11
You can use readlines if you're iterating through a file and pull out the previous lines based on a condition.
with open("myfile.txt", "r") as f:
text = f.readlines()
for row in range(0, len(text)):
if re.search("Error", text[row]):
print(text[row-1].strip())
Upvotes: -1
Reputation: 362557
You have a misunderstanding about loops in Python. The for
loop doesn't care what you do with i
at each iteration, because it is not related to the logic of the loop at all. Modifying i
just rebinds a local variable.
You would need to use a while loop to achieve the behaviour you're expecting, where the state of i
does affect the control flow of the loop:
import random
i = 0
while i < 5:
print(i)
i += 1
if random.choice([True, False]):
i -= 1
Upvotes: 5
Reputation: 214949
In Python it's possible to set up a two-way exchange between an iterator (what comes after in
in a for..in
loop) and its consumer (code inside the loop). To achieve this, you can use send
in the consumer code to "inject" a value in a generator. In your case, you can simply send back the current value once the condition is met and wrap the range
call in a generator that repeats whatever is sent back to it. Here's some code for you to play, intentionally verbose for clarity:
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)
Upvotes: 1
Reputation: 8837
Repeating many other answers, and just for completeness, you will need to use a while loop
.
i = 0
while i < 5:
print(i)
if (not condition):
i+=1
If you want to move back an iteration in the loop (instead of repeating an iteration), then use this:
i = 0
while i < 5:
print(i)
if (condition):
i -= 1
else:
i += 1
Essentially, while i < 5
evaluates upon each iteration, and checks if i < 5
. Thus by decrementing/not changing i
, we get something like this: (values of i
)
Not changing: 1->2->3-(condition satisfied)> 3 -> 4 -> 5
Decrementing: 1->2->3-(condition satisfied)>2 -> 3 -> 4 -> 5
The reason why i=i-1
in your for loop doesn't make it repeat the iteration is simple. In the for
loop, i
is assigned the value of the next item in the for loop. Python could care less about what you do with i
, as long as it is able to assign the next item to it. Thus, the for loop for i in <your_iterable>:<do whatever>
is closer to this:
_i = 0
_length = len(<your_iterable>)
while _i < _length:
i = _i
_i += 1
<do whatever>
However, in this analogy, you wouldn't be able to access the _
predicated variables (_i
,_length
). This is how I simplify the logic of the for loop
. Note that regardless of what i
is assigned to, it will be assigned to _i
upon the next iteration, and the loop really doesn't care about what i
is.
Upvotes: 3
Reputation: 12755
Python loop using range
are by-design to be different from C/C++/Java for
-loops. For every iteration, the i is set the the next value of range(5)
, no matter what you do to i
in between.
You could use a while-loop instead:
i = 0
while i<5:
print i
if condition:
continue
i+=1
But honestly: I'd step back and think again about your original problem. Probably you'll find a better solution as such loops are always error-prone. There's a reason why Python for
-loops where designed to be different.
Upvotes: 9
Reputation: 5861
range(5)
creates a list with numbers 0
thru 4
in it - [0, 1, 2, 3, 4]
.
When you run a for loop over it, you are iterating over the list. Doing i-= 1
will only decrement the value of that particular element of the list, and the iteration will continue.
Like the other answers here have suggested, you should use a while
loop.
i= 0
while i<5:
# do stuff
if #condition:
i-= 1 # or +
i+= 1
Upvotes: 3
Reputation: 26040
Utilize a while
loop:
i = 0
while i < 5:
print(i)
if condition:
i -= 1
i += 1
As has been mentioned, this is rather unidiomatic Python. Perhaps if you post what you are trying to achieve we can give some better advice.
Upvotes: 1
Reputation: 86708
for
loops in Python always go forward. If you want to be able to move backwards, you must use a different mechanism, such as while
:
i = 0
while i < 5:
print(i)
if condition:
i=i-1
i += 1
Or even better:
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
Upvotes: 44