Breaking out of a while loop - python

I am new to python and programming and having difficulty breaking out of a while loop that calls a few functions. I have tried a variety of different options but they all end the same, well they don't end it just keeps running. I am only on here because I have really researched and tried for a long time to fix this. Below is some of the code where you can see there might be confusion with a function. I am not posting the full program just the last part. Thank you for any assistance while I learn. This is also my first time posting, I've been using stackoverflow for the past year dabbling.
def main():
choice = input('''Hello,
Would you like to do basic math or return an average?
Please select 1 for basic math and 2 for average and 3 to quit:
''')
if choice == '1':
print(performCalculation())
elif choice == '2':
print(calculateAverage())
elif choice == '3':
print(main())
j = 0
k = 0
while j < 3:
print(main())
while k == 3:
break
print('All Done!')

Simply change
j = 0
k = 0
while j < 3:
print(main())
while k == 3:
break
print('All Done!')
to
j = 0
while j < 3:
print(main())
j += 1
print('All Done!')
The reason your while loop never breaks is because you have while j < 3:, but you never change the value of j, so if it was smaller to begin with, it will forever be smaller.
Also, k will never equal to 3, and even if it will, the break statement within that while loop will only make that while loop terminate, not the main one.

You have several basic mistakes here. I'll go in order of your program execution.
You aren't incrementing your loop variables.
You've started your loop variables with j and k (why not i and j?) set to zero, and are looped based on the value of these variables. Since they are never incremented, your loop never hits an exit condition.
You can increment the variables with j += 1, and k += 1 at the end of the respective loops.
Your loops are "unpythonic"
These would typically be written as my example below. You don't need to declare i separately, or increment it here. Python handles that for you.
for i in range(0, 3):
...
You're printing a function that doesn't return anything.
Your main function doesn't have a return value, so calling print(main()) is nonsense. You can replace this with simply main() unless you change main() to have some kind of return "foo" statement.

Related

It should have been an infinite loop

I wrote a code in python. While changing the code, I asked myself what should be the output.
I also answered myself it should be an infinite loop. Then I ran it. But surprisingly it wasn't an infinite loop. My question is why ?
i=0
for i in range(10):
if i == 5:
i -=1
else:
print(i)
i+=1
It's very basic in python. For your information, the range() function generates a list. Here range(5) means [0,1,2,3,4].
So i iterates through the list [0,1,2,3,4] one by one. i doesn't hold the same value initialized from the beginning like a while loop condition.
for i in [0,1,2,3,4]:
if i==5:
i-=1
else:
print(i)
i+=1
Your code and this code perform similarly. The next value of i doesn't depend on the previous value of i but on the objects of the list.
Further study might be helpful for you.
range(10) produces the sequence 0,1,...,9 from which your i variable takes its values in the loop. The fact that you do i -= 1 when i == 5 won't make i to switch back and forth from 5 to 4 on and on because i is taking its values from range(10). What happens when i == 5 is that it becomes i == 4 when you do i -= 1 but at the next iteration i will take the next value from the range which would be 6, and so on until the loop ends.
Here's an infinite loop:
i=0
while i < 10:
if i == 5:
i -=1
else:
print(i)
i+=1

Get stuck in a 'while True' loop python

I just learned about break and return in Python.
In a toy code that I wrote to get familiar with the two statements, I got stuck in a loop, but I don't know why. Here is my code:
def break_return():
while True:
for i in range(5):
if i < 2:
print(i)
if i == 3:
break
else:
print('i = ', i)
return 343
break_return()
I'm new to programming, any suggestions will be appreciated.
With the for-else construct you only enter the else block if the for loop does not break, which your for loop always does because i inevitably becomes 3 with your range generator. Your infinite while loop is therefore never able to reach the return statement, which is only in the said else block.
nvm I'm super wrong here
First of all, when you define a function in Python, any code that belongs in the function should be in the same indentation block. With this in mind, your code would look like this:
def break_return():
while True:
for i in range(5):
if i < 2:
print(i)
if i == 3:
break
else:
print('i = ', i)
return 343
break_return()
The next problem I see is that your else statement isn't correctly formatted with an if statement. If you mean for it to go on the 2nd if statement, your code would look like this:
def break_return():
while True:
for i in range(5):
if i < 2:
print(i)
if i == 3:
break
else:
print('i = ', i)
return 343
break_return()
This is only formatting. But in this example, the code would only run once because it immediately returns and exits the function.
I think this may be a better example of using both break and return:
def break_return(value):
for i in range(5):
print(i)
if i == 3:
break #This exits the for loop
if i == 4:
print("This won't print!")
#Won't print because the loop "breaks" before i ever becomes 4
return value * 2 #Returns the input value x 2
print(break_return(30)) #Display the return value of break_return()
This demonstrates how break exits a for loop and how return can return a value from the function.
The output of the code above is:
0 #Value of i
1 #Value of i
2 #Value of i
3 #Value of i
60 #The value returned by the function
Glad to hear you're learning Python! It's a lot of fun, and super useful.

Loop and validation in number guessing game

I have previously studied Visual Basic for Applications and am slowly getting up to speed with python this week. As I am a new programmer, please bear with me. I understand most of the concepts so far that I've encountered but currently am at a brick wall.
I've written a few functions to help me code a number guessing game. The user enters a 4 digit number. If it matches the programs generated one (I've coded this already) a Y is appended to the output list. If not, an N.
EG. I enter 4567, number is 4568. Output printed from the list is YYYN.
import random
def A():
digit = random.randint(0, 9)
return digit
def B():
numList = list()
for counter in range(0,4):
numList.append(A())
return numList
def X():
output = []
number = input("Please enter the first 4 digit number: ")
number2= B()
for i in range(0, len(number)):
if number[i] == number2[i]:
results.append("Y")
else:
results.append("N")
print(output)
X()
I've coded all this however theres a few things it lacks:
A loop. I don't know how I can loop it so I can get it to ask again. I only want the person to be able to guess 5 times. I'm imagining some sort of for loop with a counter like "From counter 1-5, when I reach 5 I end" but uncertain how to program this.
I've coded a standalone validation code snippet but don't know how I could integrate this in the loop, so for instance if someone entered 444a it should say that this is not a valid entry and let them try again. I made an attempt at this below.
while myNumber.isnumeric() == True and len(myNumber) == 4:
for i in range(0, 4)):
if myNumber[i] == progsNumber[i]:
outputList.append("Y")
else:
outputList.append("N")
Made some good attempts at trying to work this out but struggling to patch it all together. Is anyone able to show me some direction into getting this all together to form a working program? I hope these core elements that I've coded might help you help me!
To answer both your questions:
Loops, luckily, are easy. To loop over some code five times you can set tries = 5, then do while tries > 0: and somewhere inside the loop do a tries -= 1.
If you want to get out of the loop ahead of time (when the user answered correctly), you can simply use the break keyword to "break" out of the loop. You could also, if you'd prefer, set tries = 0 so loop doesn't continue iterating.
You'd probably want to put your validation inside the loop in an if (with the same statements as the while loop you tried). Only check if the input is valid and otherwise continue to stop with the current iteration of your loop and continue on to the next one (restart the while).
So in code:
answer = [random.randint(0, 9) for i in range(4)]
tries = 5
while tries > 0:
number = input("Please enter the first 4 digit number: ")
if not number.isnumeric() or not len(number) == len(answer):
print('Invalid input!')
continue
out = ''
for i in range(len(answer)):
out += 'Y' if int(number[i]) == answer[i] else 'N'
if out == 'Y' * len(answer):
print('Good job!')
break
tries -= 1
print(out)
else:
print('Aww, you failed')
I also added an else after the while for when tries reaches zero to catch a failure (see the Python docs or maybe this SO answer)

For Loop Not Breaking (Python)

I'm writing a simple For loop in Python. Is there a way to break the loop without using the 'break' command. I would think that by setting count = 10 that the exit condition would be met and the loop would stop. But that doesn't seem to be the case.
NOTE: Part of the challenge is to use the FOR loop, not the WHILE loop.
import random
guess_number = 0
count = 0
rand_number = 0
rand_number = random.randint(0, 10)
print("The guessed number is", rand_number)
for count in range(0, 5):
guess_number = int(input("Enter any number between 0 - 10: "))
if guess_number == rand_number:
print("You guessed it!")
count = 10
else:
print("Try again...")
count += 1
I'm new to programming, so I'm just getting my feet wet. I could use a 'break' but I'm trying figure out why the loop isn't ending when you enter the guessed number correctly.
The for loop that you have here is not quite the same as what you see in other programming languages such as Java and C. range(0,5) generates a list, and the for loop iterates through it. There is no condition being checked at each iteration of the loop. Thus, you can reassign the loop variable to your heart's desire, but at the next iteration it will simply be set to whatever value comes next in the list.
It really wouldn't make sense for this to work anyway, as you can iterate through an arbitrary list. What if your list was, instead of range(0,5), something like [1, 3, -77, 'Word', 12, 'Hello']? There would be no way to reassign the variable in a way that makes sense for breaking the loop.
I can think of three reasonable ways to break from the loop:
Use the break statement. This keeps your code clean and easy to understand
Surround the loop in a try-except block and raise an exception. This would not be appropriate for the example you've shown here, but it is a way that you can break out of one (or more!) for loops.
Put the code into a function and use a return statement to break out. This also allows you to break out of more than one for loop.
One additional way (at least in Python 2.7) that you can break from the loop is to use an existing list and then modify it during iteration. Note that this is a very bad way to it, but it works. I'm not sure that this will this example will work in Python 3.x, but it works in Python 2.7:
iterlist = [1,2,3,4]
for i in iterlist:
doSomething(i)
if i == 2:
iterlist[:] = []
If you have doSomething print out i, it will only print out 1 and 2, then exits the loop with no error. Again, this is a bad way to do it.
You can use while:
times = 5
guessed = False
while times and not guessed:
guess_number = int(input("Enter any number between 0 - 10: "))
if guess_number == rand_number:
print("You guessed it!")
guessed = True
else:
print("Try again...")
times -= 1
For loops in Python work like this.
You have an iterable object (such as a list or a tuple) and then you look at each element in the iterable, storing the current value in a specified variable
That is why
for i in [0, 1, 2, 3]:
print item
and
for j in range(4):
print alist[j]
work exactly the same. i and j are your storage variables while [0, 1, 2, 3] and range(4) are your respective iterables. range(4) returns the list [0, 1, 2, 3] making it identical to the first example.
In your example you try to assign your storage variable count to some new number (which would work in some languages). In python however count would just be reassigned to the next variable in the range and continue on. If you want to break out of a loop
Use break. This is the most pythonic way
Make a function and return a value in the middle (I'm not sure if this is what you'd want to do with your specific program)
Use a try/except block and raise an Exception although this would be inappropriate
As a side note, you may want to consider using xrange() if you'll always/often be breaking out of your list early.
The advantage of xrange() over range() is minimal ... except when ...
all of the range’s elements are never used (such as when the loop is
usually terminated with break)
As pointed out in the comments below, xrange only applies in python 2.x. In python 3 all ranges function like xrange
In Python the for loop means "for each item do this". To end this loop early you need to use break. while loops work against a predicate value. Use them when you want to do something until your test is false. For instance:
tries = 0
max_count = 5
guessed = False
while not guessed and tries < max_count:
guess_number = int(input("Enter any number between 0 - 10: "))
if guess_number == rand_number:
print("You guessed it!")
guessed = True
else:
print("Try again...")
tries += 1
What #Rob Watts said: Python for loops don't work like Java or C for loops. To be a little more explicit...
The C "equivalent" would be:
for (count=0; count<5; count++) {
/* do stuff */
if (want_to_exit)
count=10;
}
... and this would work because the value of count gets checked (count<5) before the start of every iteration of the loop.
In Python, range(5) creates a list [0, 1, 2, 3, 4] and then using for iterates over the elements of this list, copying them into the count variable one by one and handing them off to the loop body. The Python for loop doesn't "care" if you modify the loop variable in the body.
Python's for loop is actually a lot more flexible than the C for loop because of this.
What you probably want is to use break and to avoid assigning to the count variable.
See the following, I've edited it with some comments:
import random
guess_number = 0
count = 0
rand_number = 0
rand_number = random.randint(0, 10)
print("The guessed number is", rand_number)
# for count in range(0, 5): instead of count, use a throwaway name
for _ in range(0, 5): # in Python 2, xrange is the range style iterator
guess_number = int(input("Enter any number between 0 - 10: "))
if guess_number == rand_number:
print("You guessed it!")
# count = 10 # instead of this, you want to break
break
else:
print("Try again...")
# count += 1 also not needed
As others have stated the Python for loop is more like a a traditional foreach loop in the sense that it iterates over a collection of items, without checking a condition. As long as there is something in the collection Python will take them, and if you reassign the loop variable the loop won't know or care.
For what you are doing, consider using the for ... break ... else syntax as it is more "Pythonic":
for count in range(0, 5):
guess_number = int(input("Enter any number between 0 - 10: "))
if guess_number == rand_number:
print("You guessed it!")
break
else:
print("Try again...")
else:
print "You didn't get it."
As your question states NOTE: Part of the challenge is to use the FOR loop, not the WHILE loop and you don't want to use break, you can put it in a function and return when the correct number is guessed to break the loop.
import random
def main():
guess_number = 0
count = 0
rand_number = 0
rand_number = random.randint(0, 10)
print("The guessed number is", rand_number)
for count in range(0, 5):
guess_number = int(input("Enter any number between 0 - 10: "))
if guess_number == rand_number:
print ("You guessed it!")
return
else:
print("Try again...")

Else clause on Python while statement

I've noticed the following code is legal in Python. My question is why? Is there a specific reason?
n = 5
while n != 0:
print n
n -= 1
else:
print "what the..."
Many beginners accidentally stumble on this syntax when they try to put an if/else block inside of a while or for loop, and don't indent the else properly. The solution is to make sure the else block lines up with the if, assuming that it was your intent to pair them. This question explains why it didn't cause a syntax error, and what the resulting code means. See also I'm getting an IndentationError. How do I fix it?, for the cases where there is a syntax error reported.
The else clause is only executed when your while condition becomes false. If you break out of the loop, or if an exception is raised, it won't be executed.
One way to think about it is as an if/else construct with respect to the condition:
if condition:
handle_true()
else:
handle_false()
is analogous to the looping construct:
while condition:
handle_true()
else:
# condition is false now, handle and go on with the rest of the program
handle_false()
An example might be along the lines of:
while value < threshold:
if not process_acceptable_value(value):
# something went wrong, exit the loop; don't pass go, don't collect 200
break
value = update(value)
else:
# value >= threshold; pass go, collect 200
handle_threshold_reached()
The else clause is executed if you exit a block normally, by hitting the loop condition or falling off the bottom of a try block. It is not executed if you break or return out of a block, or raise an exception. It works for not only while and for loops, but also try blocks.
You typically find it in places where normally you would exit a loop early, and running off the end of the loop is an unexpected/unusual occasion. For example, if you're looping through a list looking for a value:
for value in values:
if value == 5:
print "Found it!"
break
else:
print "Nowhere to be found. :-("
Allow me to give an example on why to use this else-clause. But:
my point is now better explained in Leo’s answer
I use a for- instead of a while-loop, but else works similar (executes unless break was encountered)
there are better ways to do this (e.g. wrapping it into a function or raising an exception)
Breaking out of multiple levels of looping
Here is how it works: the outer loop has a break at the end, so it would only be executed once. However, if the inner loop completes (finds no divisor), then it reaches the else statement and the outer break is never reached. This way, a break in the inner loop will break out of both loops, rather than just one.
for k in [2, 3, 5, 7, 11, 13, 17, 25]:
for m in range(2, 10):
if k == m:
continue
print 'trying %s %% %s' % (k, m)
if k % m == 0:
print 'found a divisor: %d %% %d; breaking out of loop' % (k, m)
break
else:
continue
print 'breaking another level of loop'
break
else:
print 'no divisor could be found!'
The else-clause is executed when the while-condition evaluates to false.
From the documentation:
The while statement is used for repeated execution as long as an expression is true:
while_stmt ::= "while" expression ":" suite
["else" ":" suite]
This repeatedly tests the expression and, if it is true, executes the first suite; if the expression is false (which may be the first time it is tested) the suite of the else clause, if present, is executed and the loop terminates.
A break statement executed in the first suite terminates the loop without executing the else clause’s suite. A continue statement executed in the first suite skips the rest of the suite and goes back to testing the expression.
The else clause is only executed when the while-condition becomes false.
Here are some examples:
Example 1: Initially the condition is false, so else-clause is executed.
i = 99999999
while i < 5:
print(i)
i += 1
else:
print('this')
OUTPUT:
this
Example 2: The while-condition i < 5 never became false because i == 3 breaks the loop, so else-clause was not executed.
i = 0
while i < 5:
print(i)
if i == 3:
break
i += 1
else:
print('this')
OUTPUT:
0
1
2
3
Example 3: The while-condition i < 5 became false when i was 5, so else-clause was executed.
i = 0
while i < 5:
print(i)
i += 1
else:
print('this')
OUTPUT:
0
1
2
3
4
this
My answer will focus on WHEN we can use while/for-else.
At the first glance, it seems there is no different when using
while CONDITION:
EXPRESSIONS
print 'ELSE'
print 'The next statement'
and
while CONDITION:
EXPRESSIONS
else:
print 'ELSE'
print 'The next statement'
Because the print 'ELSE' statement seems always executed in both cases (both when the while loop finished or not run).
Then, it's only different when the statement print 'ELSE' will not be executed.
It's when there is a breakinside the code block under while
In [17]: i = 0
In [18]: while i < 5:
print i
if i == 2:
break
i = i +1
else:
print 'ELSE'
print 'The next statement'
....:
0
1
2
The next statement
If differ to:
In [19]: i = 0
In [20]: while i < 5:
print i
if i == 2:
break
i = i +1
print 'ELSE'
print 'The next statement'
....:
0
1
2
ELSE
The next statement
return is not in this category, because it does the same effect for two above cases.
exception raise also does not cause difference, because when it raises, where the next code will be executed is in exception handler (except block), the code in else clause or right after the while clause will not be executed.
I know this is old question but...
As Raymond Hettinger said, it should be called while/no_break instead of while/else.
I find it easy to understeand if you look at this snippet.
n = 5
while n > 0:
print n
n -= 1
if n == 2:
break
if n == 0:
print n
Now instead of checking condition after while loop we can swap it with else and get rid of that check.
n = 5
while n > 0:
print n
n -= 1
if n == 2:
break
else: # read it as "no_break"
print n
I always read it as while/no_break to understand the code and that syntax makes much more sense to me.
thing = 'hay'
while thing:
if thing == 'needle':
print('I found it!!') # wrap up for break
break
thing = haystack.next()
else:
print('I did not find it.') # wrap up for no-break
The possibly unfortunately named else-clause is your place to wrap up from loop-exhaustion without break.
You can get by without it if
you break with return or raise → the entire code after the call or try is your no-break place
you set a default before while (e.g. found = False)
but it might hide bugs the else-clause knows to avoid
If you use a multi-break with non-trivial wrap-up, you should use a simple assignment before break, an else-clause assignment for no-break, and an if-elif-else or match-case to avoid repeating non-trival break handling code.
Note: the same applies to for thing in haystack:
Else is executed if while loop did not break.
I kinda like to think of it with a 'runner' metaphor.
The "else" is like crossing the finish line, irrelevant of whether you started at the beginning or end of the track. "else" is only not executed if you break somewhere in between.
runner_at = 0 # or 10 makes no difference, if unlucky_sector is not 0-10
unlucky_sector = 6
while runner_at < 10:
print("Runner at: ", runner_at)
if runner_at == unlucky_sector:
print("Runner fell and broke his foot. Will not reach finish.")
break
runner_at += 1
else:
print("Runner has finished the race!") # Not executed if runner broke his foot.
Main use cases is using this breaking out of nested loops or if you want to run some statements only if loop didn't break somewhere (think of breaking being an unusual situation).
For example, the following is a mechanism on how to break out of an inner loop without using variables or try/catch:
for i in [1,2,3]:
for j in ['a', 'unlucky', 'c']:
print(i, j)
if j == 'unlucky':
break
else:
continue # Only executed if inner loop didn't break.
break # This is only reached if inner loop 'breaked' out since continue didn't run.
print("Finished")
# 1 a
# 1 b
# Finished
The else: statement is executed when and only when the while loop no longer meets its condition (in your example, when n != 0 is false).
So the output would be this:
5
4
3
2
1
what the...
Suppose you've to search an element x in a single linked list
def search(self, x):
position = 1
p =self.start
while p is not None:
if p.info == x:
print(x, " is at position ", position)
return True
position += 1
p = p.link
else:
print(x, "not found in list")
return False
So if while conditions fails else will execute, hope it helps!
The better use of 'while: else:' construction in Python should be if no loop is executed in 'while' then the 'else' statement is executed. The way it works today doesn't make sense because you can use the code below with the same results...
n = 5
while n != 0:
print n
n -= 1
print "what the..."
As far as I know the main reason for adding else to loops in any language is in cases when the iterator is not on in your control. Imagine the iterator is on a server and you just give it a signal to fetch the next 100 records of data. You want the loop to go on as long as the length of the data received is 100. If it is less, you need it to go one more times and then end it. There are many other situations where you have no control over the last iteration. Having the option to add an else in these cases makes everything much easier.

Categories