for
loops and the range(..)
object
If you write for i in range(..):
Python does not translate this into something like for(int i = 0; i < n; i++)
(in the C-programming language family).
Furthermore the range object is constructed once, before the for
loop. The range(..)
object, does not know which variables have been used to construct it. Once constructed, the range is fixed.
It sees range(..)
as an iterable object, and each iteration, it takes the next item the iterable yields. So whether you set the variable or not in the for
loop, has no effect for the next iteration.
In python-2.x, range(..)
is not a specific object, but a call to construct a list. So if you call range(10)
(without the for
loop), you get [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
.
Why it does not work?
So then why does the examples do not work?
a=5
for i in range(1,a):
print(i)
a=a+1
Here we construct range(..)
once. After that, the variables based on which it was constructed can change, since the range(..)
object does change anymore. Incrementing a
thus will not mean the range
object will get larger.
for i in range(1,4):
print(i)
i=i-1
The for
loop each time takes the next item of the iterable. So if we first have collected 1
from the range
loop, the next iteration, we collect 2
. This is regardless what the value of i
is.
for i in range(1,4):
print(i)
i=1
For the very same reason: for
does not take into account the previous value of i
. It only fetches the next item the iterable (here range(..)
yields). Since range(..)
is fixed, it will simply feed the for
loop the next item.
Emulating an infinite loop
So we need to construct an iterable that keeps yielding elements. A way to do this is itertools.count
:
from itertools import count
for i in count():
# ...
pass
Or in case you are not interested in any value, we can use repeat
as well:
from itertools import repeat
for _ in repeat(None):
# ...
pass