0

I am trying to make a simple calculator and want to return to the beginning of the loop if an unallowed value, like negative numbers, is input. However, I cannot figure out how to return to the beginning of the loop while already midway through without any errors.

This is what I have so far:

while True:
    try:
        height = float(input("Enter the height of the cylinder. "))
        if height <0:
            print("Only enter positive numbers.")
        else:
            radius = float(input("Enter the radius of the cylinder. "))
            if radius <0:
                print("Only enter positive numbers.")
    finally:
            volume = height*3.14159*radius**2
            print("The volume of the cylinder is",volume,"units")

I have tried searching and haven't been able to understand the other answers.

Michael S.
  • 3,050
  • 4
  • 19
  • 34
Weejaw
  • 3
  • 1
  • 2
    [continue](https://docs.python.org/3/tutorial/controlflow.html#break-and-continue-statements-and-else-clauses-on-loops) – Ignatius Reilly Sep 17 '22 at 05:55
  • 2
    Does this answer your question? [Asking the user for input until they give a valid response](https://stackoverflow.com/questions/23294658/asking-the-user-for-input-until-they-give-a-valid-response) – Gino Mempin Sep 17 '22 at 06:03
  • @GinoMempin No, because I need to restart the loop not only when non numbers are entered, but also when non-positive numbers are entered. – Weejaw Sep 17 '22 at 06:18
  • 1
    ...which is what the section on **Combining Exception Handling and Custom Validation** part of top answer shows how to do. You put the exception-handling that the `float(...)` call can raise and have your own `if height < 0` call in a loop. Then do `continue` as long as the input is invalid, and proceed with the rest of the loop (or `break` out of the loop) when it does become valid. You don't need this `finally` block, which "*runs whether or not the try statement produces an exception*". That's not the case here, you only want to compute the volume **if the input is valid**. – Gino Mempin Sep 17 '22 at 06:34
  • (Not enough space in my previous comment): See docs on [`finally`](https://docs.python.org/3/tutorial/errors.html#defining-clean-up-actions). – Gino Mempin Sep 17 '22 at 06:41

4 Answers4

2

You cannot simply use continue like this:

while True:
    try:
        height = float(input("Enter the height of the cylinder. "))
        if height < 0:
            print("Only enter positive numbers.")
            continue
        else:
            radius = float(input("Enter the radius of the cylinder. "))
            if radius <0:
                print("Only enter positive numbers.")
                continue
    finally:
            volume = height*3.14159*radius**2
            print("The volume of the cylinder is",volume,"units")

The above solution has a problem. In python, the finally clause is executed even after the continue, return or break statements. So, if you do this and enter a negative number as the height then it will print Only enter positive numbers and proceeds to ignore everything and moves to the finally clause to execute it. The problem with this is that the radius is defined inside the else clause. And the program skipped the else clause due to the continue statement. So, you cannot calculate the volume in the finally clause. finally block is always executed after leaving the try block. So, finally block is mostly used for de-allocating system resources before terminating the program if an exception occurs. The major uses of finally block are:

  1. Whenever a current method terminates abruptly, there are chances that the method may have been using resources that are allocated to it and will not be freed or closed upon the termination of the current method.
  2. In such situations finally, a block of code is used to free the resources that were allocated in the try block of code and this finally block of code is always executed regardless of the exception being handled by the except block or not.
  3. If an exception is not handled by the except the block of code after the control leaves the try block of code, the exception is raised again after the completion of the execution of finally block of code.
  4. The system resources that needs to be de-allocated is done by the finally block of code.
  5. Finally block of code can be used right after the try block of code without the except block of code but the exception that is going to be raised will not be handled.

So, I would advise you to not write your output in the finally block.

You can try the following:

while True:
    try:
        height = float(input("Enter the height of the cylinder."))
        if height < 0:
            print("Only enter positive numbers.")
            continue
        else:
            radius = float(input("Enter the radius of the cylinder."))
            if radius < 0:
                print("Only enter positive numbers.")
                continue
        volume = height*3.14159*radius**2
        print("The volume of the cylinder is",volume,"units")
    finally:
        print("Press any key to continue and e to exit.")
        key = input()
        if key == 'e':
            break
Timus
  • 10,974
  • 5
  • 14
  • 28
  • This is a good explanation, but I'd add an `except`-block: `except: print("You've entered an invalid float-string!")`. Otherwise it might be unclear why the `try` wasn't executed successfully. – Timus Sep 17 '22 at 13:26
1

You should also consider other types of invalid input - i.e., anything that cannot be converted to float

import math

while (hos := input('Enter height of cylinder or <return> to end: ')):
    try:
        if (hos := float(hos)) < 0:
            raise ValueError('Must be positive')
        if (ros := float(input('Enter radius of the cylinder: '))) < 0:
            raise ValueError('Must be positive')
        volume = hos * math.pi * ros ** 2
        print(f'Volume of cylinder is {volume:.2f} units') 
    except ValueError as e:
        print(e)
DarkKnight
  • 19,739
  • 3
  • 6
  • 22
0

Use the continue continue statement.

It will continue with the next iteration of the loop, or as you put it, return you to the begining of the loop.

while True:
    try:
        height = float(input("Enter the height of the cylinder. "))
        if height < 0:
            print("Only enter positive numbers.")
            continue
        else:
            radius = float(input("Enter the radius of the cylinder. "))
            if radius < 0:
                print("Only enter positive numbers.")
                continue
    finally:
        volume = height * 3.14159 * radius**2
        print("The volume of the cylinder is", volume, "units")
Unamata Sanatarai
  • 6,475
  • 3
  • 29
  • 51
0

You need except statement to handle ValueError exception when input is not float/int after try block. The finally clause runs whether or not the try statement produces an exception, so you might not need that.

To handle non positif number, you need continue statement on each if to go back or restart to while loop statement. But if don't want to use continue, you can change if statement to while statement combine with walrus operator (:=) and or statement to evaluate input. This will reduce the line and repeated code.

When the execution reach final calculation and print statement, you need to add break to stop looping back to the beginning. And lastly, I would change < 0 to <= 0 to avoid 0 or negative value in input.

while True:
    try:
        while (height := float(input("Enter the height of the cylinder. "))) <= 0 \
        or (radius := float(input("Enter the radius of the cylinder. "))) <= 0:
            print("Only enter positive numbers.")
        print(f'The volume of the cylinder is {(volume := height*3.14159*radius** 2)} units')
        break
    except ValueError:
        print("Invalid numbers")

Recap

  • Outer while statement will evaluate try except block to handle ValueError when input is not numbers (float/int)
  • Inner while will evaluate and handle non positif numbers in input
  • The walrus operator (:=) creates an assignment expression. The operator allows to assign a value to a variable inside an expression.
  • Break will stop the loop when the condition satisfied
Arifa Chan
  • 947
  • 2
  • 6
  • 23