-3

Why does this while loop execute the try suite even if the input is 0 ...? I thought according to the docs, the break should be immediate?

level = 1

while level != 0:
    level = int(input("Enter level (1, 2, 3)\n")) % 4

    try:
        g = ply.level_high(level)
        print("Player with highest level", level, "score is", g[0][0], "with", g[0][level])
    except:
        print("Invalid level")
Ted Klein Bergman
  • 9,146
  • 4
  • 29
  • 50
Rob
  • 33
  • 1
  • 9

4 Answers4

2

You are receiving the input after the while loop starts. Hence the remainder of the loop will execute even if the input is 0.

Rahul Iyer
  • 19,924
  • 21
  • 96
  • 190
  • so I need to put the input at the end of the loop? – Rob Aug 18 '20 at 16:03
  • @Rob Capture the input before the loop starts, if you don't want it to execute even once. Capture it within the loop as well if you want to keep capturing inputs. – Rahul Iyer Aug 18 '20 at 16:07
  • I want to keep capturing inputs. I put the input at the end of the loop which really bugs the logic out of me but it works. – Rob Aug 18 '20 at 16:14
  • @Rob if you do that, the loop is still going to execute once because the value of level is initially 1 – Rahul Iyer Aug 18 '20 at 16:16
1

The condition of the while loop is checked at the start of each iteration. So what happens is that the level becomes 0 only after it gets checked, and doesn't exit right away. The sequence of events:

level is set to 1
while loop entered
    start of first iteration: exit if level is not 0
    set level to (0 in this case)
    do your try-except

You can see that when the while condition is checked, level is not 0, and therefore the first iteration still executes.

A good way to get around this problem is shown at https://wiki.python.org/moin/WhileLoop.

In this case, you could do

level = 1

while True: #exiting of the loop is handled with the break
    level = int(input("Enter level (1, 2, 3)\n")) % 4
    if level==0: #the loop condition is inverted and moved here
        break
    try:
        g = ply.level_high(level)
        print("Player with highest level", level, "score is", g[0][0], "with", g[0][level])
    except:
        print("Invalid level")
Luke B
  • 2,075
  • 2
  • 18
  • 26
  • I did think of that but I hate that technique because if this were processor intensive that would be two checks being made where there should only be one. It feels really clunky to have a duplicate condition to exit the loop. I just feel that if I structured it better it would exit naturally, i.e. using it's own structural conditions. – Rob Aug 18 '20 at 16:18
  • @Rob Actually, only one check will be made (at the level==0 bit). The while True gets optimized directly into a jump. https://stackoverflow.com/a/3815387/5103577. Since you are using Python 3, it is just as fast as doing one check. It also mentions that in the Python Wiki link. – Luke B Aug 18 '20 at 16:20
  • I saw that. I didn't think it was explicitly saying only one check is made. But I guess it can be read that way as it only mentions breaking out from the inner suite's condition. The While True being optimised into a relative jump is very nice to know. Thanks for that. – Rob Aug 18 '20 at 16:30
1

if the try block is meant to be executed only when the user doesn't input 0 then you need the try block outside the while loop :

level = 1

while level != 0:
    level = int(input("Enter level (1, 2, 3)\n")) % 4
    if level == 0:
       print("Invalid level")

try:
    g = ply.level_high(level)
    print("Player with highest level", level, "score is", g[0][0], "with", g[0][level])
except:
     print('An Error Occurred')

Although having a naked except isn't good practice - you really need to be able to identify exactly what exception you are interested in.

Tony Suffolk 66
  • 9,358
  • 3
  • 30
  • 33
  • Seems a bit redundant to check level twice for 0 when the while loop is already doing that??? There must be a more efficient way of catching the 0 input value...I tried except ValueError: then entered a string value and it still crashed...? – Rob Aug 18 '20 at 16:09
  • Yes - if you enter a string then 'int' call will fail and generate a Value Error - normally you would wrap that in another try/except The check for zero inside the loop is to generate the 'Invalid Level' error – Tony Suffolk 66 Aug 18 '20 at 16:25
0

Sorted!!! And thank you guys! Great help.

level = 1

while True:
    try:
        level = int(input("Enter level (1, 2, 3)\n"))
        if level == 0:
            break
        g = ply.level_high(level)
        print("Player with highest level", level, "score is", g[0][0], "with", g[0][level])
    except ValueError:
        print("Invalid value")
    except IndexError:
        print("Invalid level")
Rob
  • 33
  • 1
  • 9