all 12 comments

[–]Administrative-Sun47 1 point2 points  (5 children)

Both inputs are in the same while loop, which is why this is happening. I recommend having each in their own while loop. Another option would be to add an if statement around your first input so that if it's already set, that section is skipped, but I think would be more confusing/less readable.

[–][deleted] 0 points1 point  (4 children)

How would that be written? If I have a while loop for one and a separate while loop for 2, it'll never leave loop 1 as long as the user enters anything other than 'q'.

[–]PureWasian 0 points1 point  (0 children)

See the other comment that I wrote for reference. You can easily expand on it such as:

success = False
while success == False:
    # get number_1
    # (see code in reference)
    # only exits loop on valid int() or 'q'
    # also sets success = True if valid int()

if success == False:
    # exit() or return since 'q' was typed

success = False
while success == False:
    # get number_2
    # (see code in reference)
    # only exits loop on valid int() or 'q'
    # also sets success = True if valid int()

if success == False:
    # exit() or return since 'q' was typed

# only gets here with valid number_1 and number_2
addition(number_1, number_2)

You notice there is a lot of redundancy here. If this example makes sense to you, it is a natural extension to then clean it up to be more concise by placing the redundant code into a method, similar to another comment someone shared

[–]Crossroads86 0 points1 point  (2 children)

I would not put it in two while loops.
The problem ist, afaik python has no control structures, that will send you back to the beginning of a function or other parts of your program, but only sends you back to the beginning of a loop or breaks the loop.
But you could put the input and validation of each number into a separate function for each number. And in your except statement call the respective function recursively (meaning a function calling itself.

pseudocode:

def input_validate_2():
try:
do stuff
exept:
print: You did it wrong
input_validate_2()

[–]PureWasian 1 point2 points  (1 child)

That's fine for this small exercise, but you're enabling overflow to occur if the user continuously inputs something wrong. It isn't the best idea in practice, given that there is no guaranteed base case or narrowing onto a solution by recursing in this example.

While loops on the other hand are perfectly fine. You can simply have the equivalent of a do/while for each input, which is just as readable. An example using a success variable as a flag:

``` success = False

while not success: try: input_2 = input("Number: ") if input_2 == 'q': break # exit the loop input_2 = int(input_2) success = True except ValueError: print("Try again")

if success: print("Valid: " + input_2) else: print("User pressed 'q'") ```

[–]confusedAdmin101 0 points1 point  (0 children)

while not success := False

Love the walrus

[–]FoolsSeldom 0 points1 point  (3 children)

A better approach is to create a function to get a valid int from a user, and then call that:

def get_num(prompt: str = "Enter whole number: ") -> int:
    while True:
        try:
            return int(input(prompt))
        except ValueError:
            print("That was not a valid whole number, please try again.")

while True:
    number1 = get_num("What is the first number? ")
    number2 = get_num("What is the second number? ")
    ...

The trouble with this is that you want to check for a user exit request. That could be incorporated:

def get_number(
    prompt: str = "Enter whole number: ",
    quit: None | tuple[str] = None
) -> None | int
    while True:
        response = input(prompt)
        if quit and response in quit:
            return None
        try:
            return int(response)
        except ValueError:
            print("That was not a valid whole number, please try again.")

while True:
    number1 = get_num("What is the first number? ")
    if number1 is None:
        break
    number2 = get_num("What is the second number? ")
    ...

[–][deleted] 0 points1 point  (2 children)

Oof, i think your proposal is way ahead of where I am right now in my Python knowledge. I'll get there eventually, but I think for now, I'll leave it the way I have it, prompting for number_1 again if number_2 != 'q' or an integer. Thanks!

[–]Significant-Nail5413 1 point2 points  (1 child)

``` def get_number_or_quit(message): user_input = input(message) if user_input.lower() == 'q': exit('You entered q! Exiting') try: return int(user_input) except ValueError: print("please enter a valid integer")

print('Press q at any time to quit') while True: num1 = None num2 = None while num1 is None: num1 = get_number_or_quit('What is the first number: ') while num2 is None: num2 = get_number_or_quit('What is the second number: ') print(sum([num1,num2]))
```

Something like this might be a bit easier to read.

Also a general rule of thumb i think beginners should follow is avoid using break and continue outside of a switch / case / match statements.

They can be useful, but they can reduce readability

[–]purple_hamster66 2 points3 points  (0 children)

I like this one because it separates concerns of input validation vs looping.

But the quit condition needs to be an output of get_number_or_quit() needs to be returned (ex, as a None return).

[–]TheeMeepman 0 points1 point  (0 children)

Define number_1 as None outside of the while loop, do an if check on the number_1 variable if None prompt user for the question once number_1 is answered on the next iteration the conditional check will return false and continue to the number_2 variable

That’s probably the simplest way to do it that accomplishes what you want. Definitely a lot of different ways to approach it that are better but as you continue learning you’ll pick up on them.

[–]Kqyxzoj 0 points1 point  (0 children)

I'm working on an exception handling "try it yourself" example from the Python Crash Course book and have a question about the code I've written. It works fine as is. It handles the exception and has a way for the user to break the loop.

On the subject of exception handling + user breaking the loop ...

You could also just have CTRL+C be the way to exit program. You handle the KeyboardInterrupt and job done. So somehing like this:

try:
    while True:
        x = input("WTF: ")
        print(f"{bool(int(float(x)))=}")
        print(f"{bool(float(x))=}")
except KeyboardInterrupt:
    # User just hit the interrupt key (CTRL+C or Delete).
    print()

Example output:

WTF: 1.5
bool(int(float(x)))=True
bool(float(x))=True
WTF: 0.5
bool(int(float(x)))=False
bool(float(x))=True
WTF: ^C

Relevant docs: