Python for loop - why does this not infinite loop? - python

Consider the following snippet of Python code:
x = 14
for k in range(x):
x += 1
At the end of execution, x is equal to 28.
My question: shouldn't this code loop forever? At each iteration, it checks if k is less than x. However, x is incremented within the for loop, so it has a higher value for the next comparison.

range(x) is not a "command". It creates a range object one time, and the loop iterates over that. Changing x does not change all objects that were made using it.
>>> x = 2
>>> k = range(x)
>>> list(k)
[0, 1]
>>> x += 1
>>> list(k)
[0, 1]

no, range(x) will return a list with the items[0,1,2,3,4,5,6,7,8,9,10,11,12,13] these items will be iterated. Each time that the loop body gets evaluated x's value change but this does not affects the list that was already generate.
in other words the collection that you will be iterating will be generated only one time.

It's because python for in loop have different behavior compared to for (in other languages):
range(x) is not executed in every iteration, but at first time, and then for in iterate across its elements.
If you want to change the code to run an infinite loop you can use a while instead (and in that case range(x) is pointless).

The for loop in python is not an iterator, but rather iterates over a sequence / generator i.e. any form of iterable.
Considering this, unless the iterable is infinite, the loop will not be infinite. A sequence cannot be infinite but you can possibly create/utilite an infinite generator. One possibility is to use itertools.count which generates a non-ending sequence of numbers starting from a specified start with a specified interval.
from itertools import count | for(;;) {
for i in count(0): | //An infinite block
#An infinite block | }
Alternatively, you can always utilize while loop to create a classical infinite loop
while True:
#An infinite block

Related

Python Find the mean school assignment - What is a loop?

I have been working on this assignment for about 2 weeks and have nothing done. I am a starter at coding and my teacher is really not helping me with it. She redirects me to her videos that I have to learn from every time and will not directly tell or help me on how I can do it. Here are the instructions to the assignment (said in a video, but made it into text.
Find the mean
Create a program that finds the mean of a list of numbers.
Iterate through it, and instead of printing each item, you want to add them together.
Create a new variable inside of that, that takes the grand total when you add things together,
And then you have to divide it by the length of your array, for python/java script you’ll need to use the method that lets you know the length of your list.
Bonus point for kids who can find the median, to do that you need to sort your list and then you need to remove items from the right and the left until you only have one left
All you’re doing is you need to create a variable that is your list
Create another variable that is a empty one at the moment and be a number
Iterate through your list and add each of the numbers to the variable you created
Then divide the number by the number of items that you had in the list.
Here's what I've done so far.
num = [1, 2, 3, 4, 5, 6];
total = 0;
total = (num[0] + total)
total = (num[1] + total)
total = (num[2] + total)
total = (num[3] + total)
total = (num[4] + total)
total = (num[5] + total)
print(total)
However, she tells me I need to shorten down the total = (num[_] + total) parts into a loop. Here is how she is telling me to do a loop in one of her videos.
for x in ____: print(x)
or
for x in range(len(___)): print (x+1, ____[x])
there is also
while i < len(___):
print(___[i])
i = i + 1
I really don't understand how to do this so explain it like I'm a total noob.
First of all, loops in python are of two types.
while: a while loop executes the code in a body until a condition is true. For example:
i = 0
while(i < 5):
i = i + 1
executes i = i + 1 until i < 5 is true, meaning that when i will be equal to 5 the loop will terminate because its condition becomes false.
for: a for loop in python iterates over the items of any sequence, from the first to the last, and execute its body at each iteration.
Note: in both cases, by loop body I mean the indented code, in the example above the body is i = i + 5.
Iterating over a list. You can iterate over a list:
Using an index
As each position of the array is indexed with a positive number from 0 to the length of the array minus 1, you can access the positions of the array with an incremental index. So, for example:
i = 0
while i < len(arr):
print(arr[i])
i = i + 1
will access arr[0] in the first iteration, arr[1] in the second iteration and so on, up to arr[len(arr)-1] in the last iteration. Then, when i is further incremented, i = len(arr) and so the condition in the while loop (i < arr[i]) becomes false. So the loop is broken.
Using an iterator
I won't go in the details of how an iterator works under the surface since it may be too much to absorb for a beginner. However, what matters to you is the following. In Python you can use an iterator to write the condition of a for loop, as your teacher showed you in the example:
for x in arr:
print(x)
An iterator is intuitively an object that iterates over something that has the characteristic of being "iterable". Lists are not the only iterable elements in python, however they are probably the most important to know. Using an iterator on a list allows you to access in order all the elements of the list. The value of the element of the list is stored in the variable x at each iteration. Therefore:
iter 1: x = arr[0]
iter 2: x = arr[1]
...
iter len(arr)-1: x = arr[len(arr)-1]
Once all the elements of the list are accessed, the loop terminates.
Note: in python, the function range(n) creates an "iterable" from 0 to n-1, so the for loop
for i in range(len(arr)):
print(arr[i])
uses an iterator to create the sequence of values stored in i and then i is in turn used on the array arr to access its elements positionally.
Summing the elements. If you understand what I explained to you, it should be straightforward to write a loop to sum all the elements of a list. You initialize a variable sum=0 before the loop. Then, you add the element accessed as we saw above at each iteration to the variable sum. It will be something like:
sum = 0
for x in arr:
sum = sum + x
I will let you write an equivalent code with the other two methods I showed you and do the other points of the assignment by yourself. I am sure that once you'll understand how it works you'll be fine. I hope to have answered your question.
She wants you to loop through the list.
Python is really nice makes this easier than other languages.
I have an example below that is close to what you need but I do not want to do your homework for you.
listName = [4,8,4,7,84]
for currentListValue in listName:
#Do your calculating here...
#Example: tempVar = tempVar + (currentListValue * 2)
as mentioned in the comments w3schools is a good reference for python.

Inner while loop doesn't get executed

Found that the control never reaches the inner while loop in this snippet for deleting a duplicate number
numbers=[1,6,6,7]
k=len(numbers)
i=0
j=0
while i in range(k-1):
while j in range(i+1,k):
if numbers[i] == numbers[j]:
numbers.remove(numbers[j])
k-=1
j-=1
j += 1
i += 1
print(numbers)
Your code does not make j start at i+1. Instead it starts at zero and never changes. The inner loop never runs because 0 is outside of the range you are testing.
Try this simple change:
i=0
while i < k+1:
j=i+1
while j < k:
if numbers[i] == numbers[j]:
...
The main change is moving the initialization of j inside the first while loop, so it updates each time you go through it, and never starts out less than or equal to i.
The other change I made is much less important. Rather than using i in range(...) and j in range(...) for the while loop conditions, I just did an inequality test. This is exactly the same as what the range membership test does under the covers, but avoids unnecessary testing for things that can't happen (like j being too small, now). It also makes the loop look a lot less like a for loop, which uses for i in range(...) syntax a lot (with a different meaning).
Another issue you may run into later, with some sets with multiple sets of duplicates is that your code to remove the jth element probably doesn't do what you intend. The call numbers.remove(numbers[j]) removes the first value equal to numbers[j] from the list, which is going to be the one at index i rather than the one at index j. To delete a list item by index, you want to use del numbers[j].
It doesn't reach because j and i starts at 0 value and in the inner while loop the condition is j in range(i+1, k) which means range(1, 4) and 0 in range(1, 4) would be False. Anyways, you should avoid using j and i as counters and use a for loop instead.
But the solution is easier and doesn't need to traverse the list, if you wanna remove the duplicate values, you can do as below:
numbers = [1, 6, 6, 7]
print(list(set(numbers)))
The result is: [1, 6, 7]
You could remove duplicates from a list in Python by using the dict.fromkeys().
numbers=[1,6,6,7]
final_numbers = list(dict.fromkeys(numbers))
print(final_numbers)
In this example, we use the dict.fromkeys() method to create a dictionary from numbers variable. We then use list() to convert our data from a dictionary back to a list. Then, on the final line, we print out our revised list.
Another option is to use set.
Sets are used to store collections of unique items in Python. Unlike lists, sets cannot store duplicate values.
We can convert our list to a set to remove duplicated items.
numbers=[1,6,6,7]
final_numbers = list(set(numbers))
print(final_numbers)

How to force a for loop counter to skip iterations in Python3?

I recently ran into an issue where I was using a for loop somewhat similar to this:
for i in range(lineCount(fileToBeProcessed)):
print(i)
j = doSomeStuff() #returns number of lines in the file to skip
i = i+j
print(i)
print('next_loop')
For a value of j={2,3,1} the output was:
1
3
next_loop
2
5
next_loop
.
.
My desired output:
1
3
next_loop
4
7
next_loop
.
.
Every time the next iteration started, the for loop counter i reset to the original cycle. My question is, is there a way to force the for loop to skip the iterations based on the return value j. I understand and was able to implement something similar with a while loop. However, I was curious as to how or why would Python not allow such manipulation?
It allows manipulations. But a for loop in Python works with a:
for <var> in <iterable>:
# ...
So Python does not attaches a special meaning to range(n) as a for loop: a range(n) is an iterable that iterates from 0 to n (exclusive). At the end of each iteration the next element of the iterable. It furthermore means that once you constructed a range(n), if you alter n, it has no impact on the for loop. This in contrast with for instance Java, where n is evaluated each iteration again.
Therefore you can manipulate the variable, but after the end of the loop, it will be assigned the next value of the loop.
In order to manipulate the variable, you can use a while loop:
i = 0 # initialization
while i < lineCount(fileToBeProcessed): # while loop
print(i)
j = doSomeStuff() #returns number of lines in the file to skip
i = i+j
print(i)
print('next_loop')
i += 1 # increment of the for loop is explicit here
Usually a while loop is considered to be "less safe" since you have to do the increment yourself (for all code paths in the loop). Since it is something one tends to forget, it is easier to write an endless loop.
Assuming that fileToBeProcessed is actually a file-like object, you can iterate directly over the file (i.e. over the lines in that file), or use enumerate(fileToBeProcessed) if you need the line numbers, and call next on that iterator to skip lines.
Like this (not tested):
iterator = enumerate(fileToBeProcessed) # or just iter = fileToBeProcessed
for i, line in iterator:
print(i)
j = doSomeStuff() #returns number of lines in the file to skip
for _ in range(j):
i, line = next(iterator) # advance iterator -> skip lines
print(i)
print('next_loop')
I've edited the code hope it may help
z =0
for i in range(lineCount(fileToBeProcessed)):
if i <= z: #if i is a value that you don't want to be output, then skip loop to next one
continue
print(i)
j = doSomeStuff()
cnt += 1
z = i+j #use a different variable from i since i the iterator value will not be updated
print(z)
print('next_loop')

For Loop to While Loop using IN for while loops

I am quite new to Python 2.7 so I had a couple of questions regarding using for loops to while loops.
For example: I am writing this definition
def missingDoor(trapdoor,roomwidth,roomheight,step):
safezone = []
hazardflr = givenSteps(roomwidth,step,True)
safetiles = []
for m in hazardflr:
safetiles.append((m,step))
i = 0
while i < len(safetiles):
nextSafe = safetiles[i]
if knownSafe(roomwidth, roomheight, nextSafe[0], nextSafe[1]):
if trapdoor[nextSafe[0]/roomwidth][nextSafe[0]%roomwidth] is "0":
if nextSafe[0] not in safezone:
safezone.append(nextSafe[0])
for e in givenSteps(roomwidth,nextSafe[0],True):
if knownSafe(roomwidth, roomheight, e, nextSafe[0]):
if trapdoor[e/roomwidth][e%roomwidth] is "0" and (e,nextSafe[0]) not in safetiles:
safetiles.append((e,nextSafe[0]))
i += 1
return sorted(safezone)
I am trying to turn all the for loops to a while loops, so this is currently what I have written so far. I actually dont know if we say "While e in " works near the middle of the code. But using the while loop rules, will this code do the same as the for loop one?
safezone = []
hazardflr = givenSteps(roomwidth,step,True)
safetiles = []
m=0
while m < hazardflr:
safetiles.append((m,step))
i = 0
while i < len(safetiles):
nextSafe = safetiles[i]
if knownSafe(roomwidth, roomheight, nextSafe[0], nextSafe[1]):
if trapdoor[nextSafe[0]/roomwidth][nextSafe[0]%roomwidth] is "0":
if nextSafe[0] not in safezone:
safezone.append(nextSafe[0])
e=0
while e in givenSteps(roomwidth,nextSafe[0],True):
if knownSafe(roomwidth, roomheight, e, nextSafe[0]):
if trapdoor[e/roomwidth][e%roomwidth] is "0" and (e,nextSafe[0]) not in safetiles:
safetiles.append((e,nextSafe[0]))
e+=1
i += 1
m+=1
return sorted(safezone)
thanks for any advice or help!
No, your code isn't identical.
While they look similar, for item in list and while item in list will do wildly different things.
for item in list is a syntactic way of saying for every item in the list - do something with is.
while item in list is different - a while loop iterates as long as the condition is true. The condition in this case being item in list. It doesn't update the item each iteration and if you never change what item or list are, it might never terminate. Additionally, if any given item isn't in the list it may terminate prematurely.
If you want to iterate through a list and keep a count, using while is the wrong way to go about it. Use the enumerate() function instead.
enumerate() takes a list, and returns a list of tuples, with each item from the list in order with its index, like so:
for i,m in enumerate(hazardflr):
safetiles.append((m,step))
This small change means you no longer have to track your indices manually.
If you are iterating through every item in a list in Python - use for that's what it is designed to do.
It depends on exactly what givenSteps returns, but in general, no. for x in foo evaluates foo once and then assigns x to be each element of foo in turn. while x in foo: ... x += 1, on the other hand, evaluates foo on every iteration and will end early if foo is not a contiguous sequence. For example, if foo = [0, 1, 2, 5, 6], for will use every value of foo, but while will end after 2, because 3 is not in foo. while will also differ from for if foo contains any non-integral values or values below the starting value.
while aList:
m= hazardflr.pop()
# ...
should be roughly equivelent to your other loop

Is "for x in range(3): print x" guaranteed to print "0, 1, 2" in that order?

Is a loop of the form
for x in range(3):
print x
guaranteed to output
0
1
2
in that order? In other words, if you loop over a list with a for item in mylist statement, is the loop guaranteed to start at mylist[0] and proceed sequentially (mylist[1], mylist[2], ...)?
Yes, the builtin list and range will always iterate in the order you expect. Classes define their own iteration sequence, so the iteration order will vary between different classes. Due to their nature set and dict (amongst others) won't iterate in a predictable order.
You can define any iteration sequence you want for a class. For example, you can make a list that will iterate in reverse.
class reversedlist(list):
def __iter__(self):
self.current = len(self)
return self
def next(self):
if self.current <= 0:
raise StopIteration
self.current -= 1
return self[self.current]
x = reversedlist([0, 1, 2, 3, 4, 5])
for i in x:
print i,
# Outputs 5 4 3 2 1 0
Yes it does. It is not the for loop that guarantees anything, but the range function though. range(3) gives you an iterator that returns 0, then 1 and then 2. Iterators can only be accessed one element at a time, so that is the only order the for loop can access the elements.
Other iterators (ones not generated by the range function for example) could return elements in other orders.
is the loop guaranteed to start at mylist[0] and proceed sequentially (mylist[1], mylist[2], ...)?
When you use a for loop, the list gets used as an iterator. That is, the for loop actually does not index into it. It just keeps calling the next function until there are no more elements. In this way the for loop itself has no say in what order elements gets processed.
Yes, it is.
A python for loop like this:
for e in list:
print e
can be traslated as:
iterator = list.__iter__()
while True:
try:
e = iterator.next()
except StopIteration:
break
print e
So, while the "next" method of the object iterator returns values in the "correct" order you will get the elements in the "correct" order.
For python list this is guaranteed to happen.
For more information look here and here
Yes. for loops in Python traverse a list or an iter in order. range returns a list in Python 2.x and an iterator in Python 3.x, so your for x in range(3) loop will indeed always be ordered.
However, the same cannot be said for dicts or sets. They will not be traversed in order - this is because the order of their keys is undefined.
Yes, it starts with the first element of a list and goes to the last.
Not all data types in python do that, such as dicts, but lists certainly do. range(x) certainly will.
Yes.
But with a dictionary there´s no order guaranteed.
Yes. Python docs about For Loop say:
Basically, any object with an iterable method can be used in a for loop in Python ... Having an iterable method basically means that the data can be presented in list form, where there's multiple values in an orderly fashion

Categories