-2

I want restrict the input to a range of numbers (say n). If I use while x not in range(n): x = input(), it is not working. So i put while x not in range(n): x = int(input()). It works fine unless I give any letters. After some research I came up with the following code:

x = None
while True:
try:
    while x not in range(n+1):
        x = int(input("X (1 to "+ str(n)+ ") :"))
        if x not in range(n+1):
            print("please enter a valid input")
    break
except:
    print("please enter a valid input")

I want to know if there is any way to shorten the code like merging both the while loops and or or.

7 Answers7

2

Edit Forgot about ValueError. It's best practice to explicitly catch ValueError rather than Exception because Exception might catch other things as well.

You can test the code quickly with the comparison functions built in.

As a bonus, I've used f-strings which can be easier to read.

n = 1000  # Example number
x = None
while True:
    try:
        x = int(input(f"X (1 to {n}) :"))
    except ValueError:
        print(f"{x} is not a number, please enter a number")
    else:
        if 1 <= x <= n:  # Inclusive of 1 and n, edit the comparisons if needed
            break
        else:
            print(f"{x} is not within range, please enter a valid number")
solid.py
  • 2,782
  • 5
  • 23
  • 30
jrmylow
  • 679
  • 2
  • 15
  • How this code 'won't raise an exception'? User enters anything which cant be converted into integer and Python will raise ValueError. – Aivar Paalberg Sep 18 '20 at 20:35
1

I'm assuming you want a number from 0 to n since you used range(n+1) which goes from 0 to n. If you want numbers from 1 to n, use range(1, n+1)

x = 0
while True:
    try:
        x = int(input("Enter a number"))
    except:
        print("Please enter a valid input")

    if x not in range(n+1):
        print("Please enter a valid input")
    else:
        break
Robo Mop
  • 3,485
  • 1
  • 10
  • 23
1

You can implement it with a more generic approach:

def get_valid_input(input_message, validator_fn=None):
    while True:
        try:
            i = input(input_message)
            if validator_fn is None or validator_fn(i):
                return i
        except:
            print("please enter a valid input")


x = get_valid_input('X (1 to ' + str(n) + ') :',
                    lambda i: x in range(n + 1))

The get_valid_input will by validate the input before returning it, this way, you can use the same method for other inputs as well.

solid.py
  • 2,782
  • 5
  • 23
  • 30
orlevii
  • 427
  • 4
  • 10
1

If you want to make the code shorter, here's a code snippet that may help:

x = ''
n = 10

while not (x.isdigit() and int(x) in range(1, n + 1)):
    x = input(f'X (1 to {n}): ')

To break it down, the statement x.isdigit() will ensure if x consists of only integers (a . in the string will make it False though). If that case passes it will parse the string to an integer safely and then check if it is in range. The not will make sure that if these cases fail, the loop has to continue.

Old Answer

You can use a try..except block inside a while loop like below. If the value is not an integer, an error will be thrown as soon as python tries to parse it and if the value is not in range, an Error will be thrown within the if statement both of which will be handled by the try..catch block. If no Exception is thrown, break statement will execute and break out of the loop...

n = 10
x = None

while True:
    try:
        x = int(input(f"X (1 to {n}): "))

        if x not in range(n + 1):
            raise Exception("ERROR: Not in range")

        break  # If no errors are thrown, break from the loop

    except:
        print('Please enter a valid number')

...
Melvin Abraham
  • 2,870
  • 5
  • 19
  • 33
0

Maybe you can do something like this:

while True:
    if len(input()) > 20:
        print('please input valid input')

The len() will return the length of the string that input() returns.

You could also simplify it and make it more dynamic with a lambda:

fun = lambda y, x: print('ok') if len(y) > x else print('please input a valid number')
while True: fun(input(), 5)
mama
  • 2,046
  • 1
  • 7
  • 24
0
x = 1
n = 3
while x in range(n+1):
    x = int(input("X (1 to "+ str(n)+ ") :"))
    if x not in range(n+1):
        print("please enter a valid input")
        x = 1

sequence for example:

X (1 to 3) :3
X (1 to 3) :4
please enter a valid input
X (1 to 3) :3
X (1 to 3) :2
X (1 to 3) :1
X (1 to 3) :6
please enter a valid input
X (1 to 3) :

is that what you expected?

Yossi Levi
  • 1,258
  • 1
  • 4
  • 7
0

The following code reduces the number of for loops to 1, and catches all invalid input.

n = 10
x = n + 1 

while x not in range(1, n + 1): # The loop keeps going until x is in range.
    x = input('Please enter a valid input in the range of (1, '+ str(n) +'): ')
    try:
        x = int(float(x)) # e.g 5.0 string literal gets converted to 5.
    except ValueError:
        x = n + 1 # Re-initialize x to keep iterating, until we get a valid input.
    if x in range(1, n + 1):
        print('Number in range ->', x)

Output with invalid input and integers:

Please enter a valid input in the range of (1, 10):  一二三
Please enter a valid input in the range of (1, 10): 1²
Please enter a valid input in the range of (1, 10): asd
Please enter a valid input in the range of (1, 10): word
Please enter a valid input in the range of (1, 10): a
Please enter a valid input in the range of (1, 10): 9
Number in range -> 9

Output with floating point numbers:

Please enter a valid input in the range of (1, 10): 11.0
Please enter a valid input in the range of (1, 10): 0.0
Please enter a valid input in the range of (1, 10): 5.0
Number in range -> 5
solid.py
  • 2,782
  • 5
  • 23
  • 30
  • Asking input from user and expect to get answers which never raise exception? '1²'. isnumeric() is True but converting it to int will raise ValueError. As well as any letter or float entered by user. If one is so sure in correctness of user input then no validation is needed - if asked user always provides integer in correct range. – Aivar Paalberg Sep 18 '20 at 20:32