1

Our teacher wants us to make a program that asks if you are ready and if YES or NO are typed then it should move on to the next question. For some reason he doesn't want us to use break and I can't find any command that really does anything similar to it other then continue, but continue only skips to the next line. Here is my code:

prompt = ""
while (prompt != "YES" or prompt != "NO"):
    prompt = input ("Are you ready?(YES/NO): ")
    if (prompt == "YES"):
        print("Great!")
        break
    elif (prompt == "NO"):
        print("How can I help?")
        break
    else:
        print("Error, not a valid input")

while this would work in what I'm trying to achieve, I would get failed for having the break statement. Is there any alternative to this?

martineau
  • 119,623
  • 25
  • 170
  • 301
NukeSnicks
  • 29
  • 6

2 Answers2

2

You might want to have a variable to that will check the condition such as valid_answer. Also, it is better practice to get rid of unnecessary parenthesis (if you expression is complex, they are fine, but in your case while loop condition is much simpler without them).


valid_answer = False
while not valid_answer:
    prompt = input("Are you ready?(YES/NO): ")
    if prompt == "YES":
        print("Great!")
        valid_answer = True
    elif prompt == "NO":
        print("How can I help?")
        valid_answer = True

    else:
        print("Error, not a valid input")


Ibrahim Berber
  • 842
  • 2
  • 16
  • 2
    That goes against the pythonic idiom (where you just loop on `while True` and `break` when needed). It will be sad if this is the actual answer the OP is looking for... – Tomerikoo Jun 21 '21 at 16:40
  • That would be my first intuition as well, but the OP states that their instructor wanted them to write the code _without_ `break` statements. – Ibrahim Berber Jun 21 '21 at 16:43
  • This is exactly why I said it is sad... Don't know what is the purpose of this exercise but giving bad habits – Tomerikoo Jun 21 '21 at 16:45
  • @Tomerikoo not necessarily, there are times when this style is better. For example if you needed 5 answers, `while len(answers) < 5: append_answer(answers)` is better than `while True: append_answer(answers); if len(answers) >= 5: break` – Mark Ransom Jun 21 '21 at 17:44
  • 1
    @MarkRansom: The idiom Tomerikoo refers to is the Python equivalent of the `do`/`while` or the equivalent of the `while` loop in C where the value being tested is also initialized as part of the test. Prior to the walrus operator, both were typically handled the same way (as Tomerikoo describes), since the alternative was some combination of duplicated code, variables initialized with garbage values just to pass a test on the first loop, or ugly flag values. – ShadowRanger Jun 21 '21 at 18:08
  • That said, in this case, I'd argue the handling of valid values shouldn't be in the loop at all, and even if it is, and `break` is forbidden, it's still best to avoid the unpythonic flag value and just fix the OP's test, which, as you noted, is incorrect (if fixed, the `break`s aren't strictly necessary, the code is just mildly unidiomatic due to testing the same value for the same test twice, and needing to use a garbage semi-magic value for `prompt` to enable it to pass the on entry test the first time). – ShadowRanger Jun 21 '21 at 18:09
  • @MarkRansom Of course. As Shadow explained nicely, I meant that the use of "loop flags" is un-pythonic and better handled with `while True: break`. Of course in your example it is better to use an explicit condition – Tomerikoo Jun 22 '21 at 10:45
0

You could just delete break from your code if you fixed your loop condition, changing:

while (prompt != "YES" or prompt != "NO"):

which is always true ("YES" is not equal to "NO", so the second test is true whenever the first one is false, so the loop condition is always true), with either:

while prompt != "YES" and prompt != "NO":

which is the minimal change to fix the logic (so it stops if it's equal to either value, rather than only when it's equal to both), or for a more English readability:

while prompt not in ("YES", "NO"):

which doesn't have the tricks of how != and and/or interact in boolean logic to worry about. Either way, after fixing the test, the code will work as written without the need for break at all.

To answer the broader question, the only alternatives to break are:

  1. Careful use of tests to ensure the loop condition itself terminates when desired, and no code after the condition becomes true that should only execute when false is actually executed (this is what the minimal fix described above does)
  2. Using return in a function (requires factoring the loop out of the function it is in)
  3. Using an exception and try/except to jump out of the loop.

Not coincidentally, these are also your options when you need to break out of multiple levels of a nested loop (Python has no break that can break an arbitrary number of loops). #1 is frequently unpythonic (especially if it relies on flag variables; in your case, it's okay, just mildly redundant on the tests), as is #3, so if your code can't use break, and can't be restructured to avoid the need for it, #2 is usually the best solution, especially in complex cases.


Personally, I usually wouldn't put the handling of valid cases in the loop at all, leaving the loop to run and handle only invalid cases (which can occur 0-infinity times), with the valid cases handled after the loop is complete, exactly once.

A simple solution available on Python 3.8+ is to use the walrus operator (assignment expression for boring types) and just have the loop run until the result is valid, removing the handling for valid inputs from the loop entirely, putting them outside/after the loop entirely, so for your specific problem the end result would look like:

while (prompt := input("Are you ready?(YES/NO): ")) not in ("YES", "NO"):
    print("Error, not a valid input")

if prompt == "YES":
    print("Great!")
else:  # No need for elif; only "YES" or "NO" would exit loop without throwing exception
    print("How can I help?")

Pre-3.8, you could still do the same thing, the while is just a little uglier (more repeated code):

prompt = input("Are you ready?(YES/NO): ")
while prompt not in ("YES", "NO"):
    print("Error, not a valid input")
    prompt = input("Are you ready?(YES/NO): ")

Bonus, with no particular increase in code complexity, you drop from 9-11 lines of code in your current design (9 without break or explicit flag, 11 with) to 6-8 lines (6 with walrus, 8 without). With the walrus, it's strictly better; no code is repeated, no tests are repeated multiple times per loop, the loop is kept very simple.

ShadowRanger
  • 143,180
  • 12
  • 188
  • 271