Infinite loops using 'for' in Python [duplicate] - python

This question already has answers here:
Is there an expression for an infinite iterator?
(7 answers)
Closed 5 years ago.
Why does this not create an infinite loop?
a=5
for i in range(1,a):
print(i)
a=a+1
or this
for i in range(1,4):
print(i)
i=i-1
or this
for i in range(1,4):
print(i)
i=1
Is there any way we can create infinite loops using a for loop? I know there is the while loop for that but I was just curious.

range is a class, and using in like e.g. range(1, a) creates an object of that class. This object is created only once, it is not recreated every iteration of the loop. That's the reason the first example will not result in an infinite loop.
The other two loops are not infinite because, unlike the range object, the loop variable i is recreated (or rather reinitialized) each iteration. The values you assign to i inside the loop will be overwritten as the loop iterates.

Consider a for loop:
for item in iterable:
print(item)
The idea is that as long as iterable is unchanged, we will loop through each and every item inside iterable once. For example,
for item in [3, 2, 1, 666]:
print(item)
will output 3 2 1 666. In particular, we find that range(1, 4) is a easy way to represent an iterable [1, 2, 3]. Thus,
for i in range(1, 4):
print(i)
will output 1 2 3.
Example 1
a=5
for i in range(1,a):
print(i)
a=a+1
In this case, range(1,a) is evaluated once, when the loop begins.
Example 2
for i in range(1,4):
print(i)
i=i-1
In this case, i is reevaluated every loop, before executing the print and i=i-1 statements within the body of the loop.
Example 3
for i in range(1,4):
print(i)
i=1
Just like Example 2, i is reevaluated every loop.

You can't, in this case, update the iterator that your for loop is looping over.
The range in for i in range(a): is actually a function - it takes a value, a, and returns an object that contains the values that it will loop through. Once you've built that object you can change the input variable as much as you'd like, and that object won't change.
Imagine if we made our own similar function called my_range that generates a list (whereas the built in range function generates a range):
def my_range(end):
my_list = []
for i in range(end):
my_list.append(i)
return my_list
Now if we were to use our new function, like so:
a = 4
for i in my_range(a):
print(i)
a += 1
It'd be obvious that we can't update the list object that we're looping over by changing a, because the list that we're looping over has already been made, and isn't being remade on every loop.
Can you make an infinite loop in python? Yes, just add a new entry to the object that you're looping through, e.g.:
my_list = [0]
for i in my_list:
print(i)
my_list.append(i+1)
Now we're updating the object that we're looping over.

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

range copies the parameters given to it for internal use. So changes to those afterwards have no effect. Same as with the loop variable, which is only created from the internal values every time.
That's different though if you use a mutable object like a list to iterate over:
a = [1,2,3]
for i in a:
a.append(i)
This loop will indeed run infinitely.

Because a range is either a list (Python2) or a range object both of which are finite. That range is created once before the loop starts. Your loop variable is assigned the next element of the range at the beginning of each iteration, regardless of what you assign it later in the loop body. You need an infinite iterator for an infinite for loop, e.g. itertools.cycle:
from itertools import cycle
for x in cycle(range(5)):
# endless

Related

for in loop over list (with +=) coding beginner

a = [1,2,3]
for num in a:
a = a + [num]
print(a)
>>>[1,2,3,1,2,3]
a = [1,2,3]
for num in a:
a += [num]
print(a)
>>>
The first code works as expected, so I assume the below code will work the same, but it didn't print anything. Not even a Error message.
Question:
I did some research in stackoverflow on the use of +=, but still got confused on what's the difference between the add and iadd
In the first case, you are rebinding the name a to a new value, so the variable a before the loop is not the same object as the variable a inside and after the loop. The loop is able to iterate on the original value of a.
But in the second case, you are not rebinding the name. a is the same object throughout the code. And so the loop iterates over a list that grows endlessly bigger.

How these python for loop and slicing working?

How this statement will work?
j for i in range(5)
Example:
x1=(j for i in range(5))
will yield five 4's when iterated. Why it will not yield 01234 like when we replace j with i.
How this statement working?
a = [0, 1, 2, 3]
for a[-1] in a:
print(a[-1])
0
1
2
2
Your first example is a generator expression (the parentheses are required, so the first version you show doesn't actually make sense). The generator expression repeatedly yields j, which is not defined in the code you show. But from your description, it already has the value 4 in the environment you were testing in, so you see that value repeatedly. You never use the i value, which is what's getting the values from the range.
As for your other loop, for a[-1] in a keeps rebinding the last value in the list, and then printing it.
A for loop does an assignment to the target you give it between for and in. Usually you use a local variable name (like i or j), but you can use a more complicated assignment target, like self.index or, as in this case, a[-1]. It's very strange to be rewriting a value of your list as you iterate over it, but it's not forbidden.
You never get 3 printed out, because each of the previous assignments as you iterated overwrote it in the list. The last iteration doesn't change the value that gets printed, since you're assigning a[-1] to itself.
Your first question raises error when iterating, as j is not defined. If you are getting any response from that, you probably have defined a value for j above your generator, which sounds to be 4 in your code.
About your second question:
when you have something like this:
for i in a:
...
Actually you are are doing this in each cycle: i=a[0], i=a[1], ....
When you write a[-1] in a, it is kind of equal to: a[-1]=a[0], a[-1]=a[1], ... and you are changing last element of a each time. So at the end, the last element of your list would be 2.

Why can't I increment the variable in my for loop manually? [duplicate]

C:
# include <stdio.h>
main()
{
int i;
for (i=0; i<10; i++)
{
if (i>5)
{
i=i-1;
printf("%d",i);
}
}
}
Python:
for i in range(10):
if i>5: i=i-1
print(i)
When we compile C code, it goes into a infinite loop printing 5 forever, whereas in Python it doesn't, why not?
The Python output is:
0 1 2 3 4 5 5 6 7 8
In Python, the loop does not increment i, instead it assigns it values from the iterable object (in this case, list). Therefore, changing i inside the for loop does not "confuse" the loop, since in the next iteration i will simply be assigned the next value.
In the code you provided, when i is 6, it is then decremented in the loop so that it is changed to 5 and then printed. In the next iteration, Python simply sets it to the next value in the list [0,1,2,3,4,5,6,7,8,9], which is 7, and so on. The loop terminates when there are no more values to take.
Of course, the effect you get in the C loop you provided could still be achieved in Python. Since every for loop is a glorified while loop, in the sense that it could be converted like this:
for (init; condition; term) ...
Is equivalent to:
init
while(condition) {
...
term
}
Then your for infinite loop could be written in Python as:
i = 0
while i < 10:
if i > 5:
i -= 1
print i
i += 1
The two constructs are both called for loops but they really aren't the same thing.
Python's version is really a foreach loop. It runs once for each element in a collection.
range(10) produces a list like [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] So the for loop runs once for each member of the collection. It doesn't use the value of i in deciding what the next element is, it always takes the next element in the list.
The c for loop gets translated into the equivalent of
int i = 0
while i < 10:
...
i++;
Which is why you can manipulate the i.
Because your two examples are completely different things.
range(10) in python produces a list of values 0 - 9, then for i in returns each value as i. This is generally referred to as a "for-each" loop. You are operating on a value, not the iterator, when you say i=i-1 in your python example.
http://docs.python.org/tutorial/controlflow.html
The for statement in Python differs a bit from what you may be used to in C or Pascal. Rather than always iterating over an arithmetic progression of numbers (like in Pascal), or giving the user the ability to define both the iteration step and halting condition (as C), Python’s for statement iterates over the items of any sequence (a list or a string), in the order that they appear in the sequence. For example (no pun intended):
a = ['cat', 'window', 'defenestrate']
for x in a:
print x, len(x)
It is not safe to modify the sequence being iterated over in the loop (this can only happen for mutable sequence types, such as lists). If you need to modify the list you are iterating over (for example, to duplicate selected items) you must iterate over a copy.
Of course the sequence generated by range is not mutable.

Infinite loop using a for loop python

So I'm trying to make a infinite loop that uses a for loop instead of a while loop. This is my current code. If this code works it should produce x infinitely.
Current code:
z=1
for x in range(0,z):
print(x)
z=z+1
That doesn't work because the first time you enter the for loop the range function generates a range from zero to the value of z at that point, and later changes to z does not affect it. You can do something like what you want using, for example, itertools.count:
from itertools import count
for x in count():
print(x)
range returns an iterator. The iterator is already generated and evaluated before the loop iteration. (It's the returned iterator on which the loop is iterating).
The value of z is not used after the iterator is returned hence incrementing or changing its value is no-op.
If you really want an infinite loop using for you will have to write your custom generator.
For eg:
def InfiniteLoop():
yield 1
To be used as :
for i in InfiniteLoop()
Update list after each iteration make infinite loop
list=[0]
for x in list:
list.append(x+1)
print (x)

How does a for loop know to increment

When defining a Fibonacci sequence the following code was used:
def fibonacci(n):
current=0
after=1
for i in range(1,n):
current,after=after,current+after
return after
How does the for loop know to increment by one every time we pass through? I tried using a while loop while e<=n: and it returned an error as I hadn't defined e.
A for loop in python iterates through items or generators. In your example, range(1,n) will return a list of elements between [1, n) in python2, or a generator that will yield the same items in python3.
Essentially, a for loop can iterate any kind of iterables:
for item in [1, 6, 8, 9]:
print(item)
It will print 1, 6, 8 and 9.
Using range, there is a 3rd optional parameter which allows you to specify the increment:
range(1, 10, 1) # The defaut [1 .. 9] numbers
range(1, 10, 2) # From 1 until 9 with 2 of increment
for loop does not increment, instead it iterates
The for loop does not increment, instead it is asking so called iterable to provide values to work with.
In your example, the iterable is range(1,n).
In Python 2.x, the range(1, n) creates a list of values and the for loop is only asking the list to provide next value in each run, until the list gets exhausted from values.
In Python 3.x the range(1, n) is optimized and returns special iterable type <range>, which when asked by for loop to provide next value provide it.
By default if you don't specify your step i.e for i in range (start,stop,step) the increment is considered as one otherwise it's your step that you specified.

Categories

Resources