'How to stop Python while I key in a value that indicates "break"

in the python code below, the desired output is to find the max and min from all of the key-in values (via input function) and when I key in "done", it stops (meaning that there will be no pop-up anymore), while other non-integer strings will print "Invalid output".

However, even if I key in "done", the pop-up still appears and it never ends, what is the problem of my code?

lar = None
smal = None
while True:
   try:
      num = int(input("Enter a number:"))
   except:
      if num == "done":
         break
      else:
         print("Invalid input")
   if lar is None:
      lar = num
   elif lar <= num:
      lar = num
   if smal is None:
      smal = num
   elif smal >= num:
      smal = num
print("Maximum is", lar)
print("Minimum is", smal)


Solution 1:[1]

Its because of your try/except:

...
while True:
   try:
      num = int(input("Enter a number:"))  # issue is here
   except:
      if num == "done":
         break
      else:
         print("Invalid input")
...

When you cast int() on the result of input() when you've typed "done" in the terminal, this throws a ValueError (see example of the running below):

>>> Enter a number:h
Traceback (most recent call last):
  File "main.py", line 5, in <module>
    num = int(input("Enter a number:"))
ValueError: invalid literal for int() with base 10: 'h'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "main.py", line 7, in <module>
    if num == "done":
NameError: name 'num' is not defined

In this example, the first value ever given to your while loop to try and assign to the variable num is "h", and this errors on int() since "h" is not a base 10 number (which is what int() tries to cast a string as). That ValueError is caught in the except portion of your block, but then the if num == "done" fails because num is never assigned to since the first try failed.

Lets look at another example:

>>> Enter a number:1
>>> Enter a number:h
Invalid input
>>> Enter a number:

Here we didn't receive the error traceback, but why?

Well the fact that we gave a valid base 10 integer as our first input, in this case "1", it was successfully assigned to the variable num and thus the if/else inside the except block executes correctly since num currently holds "1".

To resolve your issue, your loop needs to look like this:

lar = None
smal = None
while True:
  # never give variables the same name as keywords
  inpt = input('Enter a number (or done): ')
  
  if inpt == 'done':
      break
    
  try: 
    num = int(inpt)
  except ValueError as err:
    # f-string to display error
    print(f'Invalid input: {inpt}')

  if not lar:
    lar = num
  elif lar <= num:
    lar = num

  if not smal:
    smal = num
  elif smal >= num:
    smal = num
    
print("Maximum is", lar)
print("Minimum is", smal)

>>> Enter a number (or done): 1
>>> Enter a number (or done): 8
>>> Enter a number (or done): 3
>>> Enter a number (or done): 2
>>> Enter a number (or done): -1
>>> Enter a number (or done): 4
>>> Enter a number (or done): done
Maximum is 8
Minimum is -1

Personally I'd adjust even further using built-ins:

nums = []
while True:
  # never give variables the same name as keywords
  inpt = input('Enter a number (or done): ')
  
  if inpt == 'done':
      break
    
  try: 
    num = int(inpt)
  except ValueError as err:
    # f-string to display error
    print(f'Invalid input: {inpt}')

  nums.append(num)
    
print("Maximum is", max(nums))
print("Minimum is", min(nums))

Solution 2:[2]

When a user inputs "done", it is then trying to be converted into an int. This throws an error and the value of num is not set, so when it is checked if it is equal to "done" it will never be. You should set check the user input before attempting to convert to an int.

lar = None
smal = None
while True:
    try:
        user_input =input("Enter a number:")
        if user_input == "done":
            break
        num = int(user_input)
    except:
        print("Invalid input")
    if lar is None:
        lar = num
    elif lar <= num:
        lar = num
    if smal is None:
        smal = num
    elif smal >= num:
        smal = num
    print("Maximum is", lar)
    print("Minimum is", smal)

Solution 3:[3]

When the exception is raised, the new value that is inputted is never saved to the num variable.

You could add the if-statement before converting the input to an integer.

Here's a quick example:

num = input("Enter a number:")
if num == "done":
        break
try:
    num = int(num)
except ValueErorr:
    print("Invalid input")

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 pstatix
Solution 2 bthalpin
Solution 3