Is there a way to check the type of an input, then loop back to the input if the type is incorrect?

Question:

def set_values():
    loopCtrl = 1
    while loopCtrl == 1:
        loopCtrl = 2
        juvenilePopulation = int(input("Enter the population of the juvenile greenfly (1000s) > "))
        if not isinstance(juvenilePopulation, int): loopCtrl = 1
        juvenileSurvivalRate = float(input("Enter the survival rate of juvenile greenfly (decimal) > "))
        if not isinstance(juvenileSurvivalRate, float): loopCtrl = 1
        adultPopulation = int(input("Enter the population of the adult greenfly (1000s) > "))
        if not isinstance(adultPopulation, int): loopCtrl = 1
        adultSurvivalRate = float(input("Enter the survival rate of adult greenfly (decimal) > "))
        if not isinstance(adultSurvivalRate, float): loopCtrl = 1
        senilePopulation = int(input("Enter the population of the senile greenfly (1000s) > "))
        if not isinstance(senilePopulation, int): loopCtrl = 1
        senileSurvivalRate = float(input("Enter the survival rate of senile greenfly (decimal) > "))
        if not isinstance(senileSurvivalRate, float): loopCtrl = 1
        birthRate = float(input("Enter the birthrate of the greenfly > "))
        if not isinstance(birthRate, float): loopCtrl = 1

I have this admittedly ugly chunk of code, that currently just asks for a bunch of inputs, assigns it to variables, and then checks the type of the variable, before looping back around to the top. What I really want to achieve is for the code to loop back to the input statement that had the incorrect input rather than the beginning, but in a way that is more pythonistic than a ton of while loops.

Asked By: traditionallimb

||

Answers:

Replace your calls to input with a function like this:

def get_value(prompt, validator):
    while True:
        try:
            return validator(input(prompt))
        except ValueError as err:
            print(f"  Invalid value, please try again: {err}")

You would call it like this:

juvenilePopulation = get_value("Enter the population of the juvenile greenfly (1000s) > ", int)
juvenileSurvivalRate = get_value("Enter the survival rate of juvenile greenfly (decimal) > ", float)

Running the above code looks something like this:

Enter the population of the juvenile greenfly (1000s) > foo
  Invalid value, please try again: invalid literal for int() with base 10: 'foo'
Enter the population of the juvenile greenfly (1000s) > 1.1
  Invalid value, please try again: invalid literal for int() with base 10: '1.1'
Enter the population of the juvenile greenfly (1000s) > 12
Enter the survival rate of juvenile greenfly (decimal) > bar
  Invalid value, please try again: could not convert string to float: 'bar'
Enter the survival rate of juvenile greenfly (decimal) > 0.1

Note that in this example we’re using basic types like int and float for validation, but you could just as easily pass in a custom function. For example, if the survival rate needs to be between 0 and 1, you could write:

def validateSurvivalRate(v):
    v = float(v)
    if not 0 < v < 1:
      raise ValueError("surival rate must be between 0 and 1")
    return v

juvenileSurvivalRate = get_value("Enter the survival rate of juvenile greenfly (decimal) > ", validateSurvivalRate)

Which would look like:

Enter the survival rate of juvenile greenfly (decimal) > foo
  Invalid value, please try again: could not convert string to float: 'foo'
Enter the survival rate of juvenile greenfly (decimal) > 1.1
  Invalid value, please try again: surival rate must be between 0 and 1
Enter the survival rate of juvenile greenfly (decimal) > -4
  Invalid value, please try again: surival rate must be between 0 and 1
Enter the survival rate of juvenile greenfly (decimal) > 0.4
Answered By: larsks

Try like this. I’m not sure this is the best practice but you reuse code this code. you can add extra datatypes also

def process_values(input_string, input_values, data_type):
    try:
        if not isinstance(eval(input_values), data_type):
            input_values = input(input_string)
            process_values(input_string, input_values, data_type)
    except NameError:
        print('Invalid input')
        input_values = input(input_string)
        process_values(input_string, input_values, data_type)


input_strings = ['Enter the population of the juvenile greenfly (1000s) > ',
                 'Enter the survival rate of juvenile greenfly (decimal) > ',
                 'Enter the population of the adult greenfly (1000s) > ',
                 'Enter the survival rate of adult greenfly (decimal) > ',
                 'Enter the population of the senile greenfly (1000s) > ',
                 'Enter the survival rate of senile greenfly (decimal) >'
                 'Enter the birthrate of the greenfly > '
                 ]

data_types = [int, float, int, float, int, float, float]

for input_string, data_type in zip(input_strings, data_types):
    input_values = input(input_string)
    process_values(input_string, input_values, data_type)

here i have handled errors also. if you need more exceptions condition you can add it there.

Answered By: Dev
Categories: questions Tags: ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.