1
def p_parameter(p):

     if p < 10 or p > 100:
        int(input("Please try again: "))
        newp = p
        return newp
    else:
        newp <10 or newp >100
        input("Good bye")
        bye()

def main():

        speed(0)
        R=100
        r=4
        p=int(input("Please enter a number between 10 and 100: "))
        p_parameter(p)
        t_iter(R,r,p)
        Xcord(R,r,p,t_iter(R,r,p))
        Ycord(R,r,p,t_iter(R,r,p))
        input("Hit enter to close porgram")
        bye()

main()

Here is my code for a program which draws a spirograph. The program runs fine but what I have posted here is my attempt to have the user enter a value between 10-100 for p.

What I want to do is check to see if p is < 10 or p > 100. If it is, then give the user a chance to re-enter a new value of p and use that value as long as it fits the allowed limits. After the second check if the user still has entered an incorrect value of p I want the program to close.

The problem is that it checks for 'p' then asks for p again but it only take the first value of 'p', and does not preform the second check or give p its new value.

Pacific Stickler
  • 1,078
  • 8
  • 20
Cos
  • 129
  • 2
  • 13

2 Answers2

0

You should probably just prompt in the function. This is the standard idiom for writing these kinds of validations:

def validate():
    while True:
        # begin inf. loop
        p = input("some prompt goes here")
        if some_validation:
            break
            # end inf. loop
        # therefore if the validation fails, it reprompts
    # once you're out of the inf. loop...
    return p

This is one of those things you could build a pretty good decorator for

def validate(validation, not_valid_warning=None):
    if not hasattr(validation, '__call__'):
        raise TypeError("validation must be callable")
    def wrapper(f):
        def wrapped(*args):
            while True:
                p = f(*args)
                if validation(p):
                    break
                if not_valid_warning:
                    print(not_valid_warning)
            return p
        return wrapped
    return wrapper

@validate(lambda x: x < 10 or x > 100)
def v_input(*args):
    return __builtins__.input(*args)

# Example..........
if __name__ == "__main__":
    v_input("Enter a number less than 10 or more than 100: ")
Adam Smith
  • 52,157
  • 12
  • 73
  • 112
  • def validate(): while True: p=int(input("Please enter a number between 10 and 100: ")) if p < 10 or p > 100: break return p so I did this put now my other function do not have p defined – Cos Sep 11 '14 at 18:32
  • in your `main` function you'll need to do `p = validate()` rather than `p = input('whatever'); validate()` – Adam Smith Sep 11 '14 at 18:38
0

Problems with your solution & Corrections:

it only take the first value of p and does not give p its new value.

  1. you ask the user for p again, but do not assign this new value to newp variable, like so:

    newp = int(input("Please try again: "))
    

does not preform the second check.

  1. your else statement is checking for condition on newp outside the scope of the newp variable, which is inside the if statement. You should encapsulate your check on newp variable inside the if statement, like so:

    def p_parameter(p):
        if p < 10 or p > 100:
            newp = int(input("Please try again: "))
            if newp <10 or newp >100:
    
  2. you don't have return statements inside the p_parameter() function for the instances when the program does not enter the if statement. So it should instead be like this:

    def p_parameter(p):
        if p < 10 or p > 100:
            newp = int(input("Please try again: "))
            if newp <10 or newp >100:
                print( "Good Bye")
                bye()
            else: 
                return newp    # need return statements like this
        else:
            return p           # need return statements like this
    

Suggested Solution to your questions:

What I want to do is check to see if 'p' is < 10 or 'p' > 100, if it is then give the user a chance to reenter a new value of 'p' and use that value as long as it fits within the allowed parameters.

  1. use a while True: infinite loop with the break statement to exit if the correct answer is received.
  2. use try, except and else block with the ValueError

    1. to catch any errors due to inputs that are not integers.
    2. to detect any inputs that are out of the allowed range.

After the second check if the user still has entered an incorrect value of 'p' I want the program to close.

In order to close the program, you can either:

  1. let the user hit ctrl+c (my personal preference), or
  2. put a counter of how many times the while loop should be run to check for new input, and then force the program to exit if a limit is reached by using sys.exit(0) (Note: First You'll need to import sys to use it; I think your bye() is doing just that).

Putting it all together:

  1. In your main() function, remove the input() statement and only have a call to p_parameter() function, like so: p = p_parameter()

  2. Define p_parameter() function as follows:

    import sys
    def p_parameter():
        exit_counter = 1    # counter to exit after 2 tries
    
        while True:
            try:
                p = int( input( "Please enter a number between 10 and 100: ") )
            except ValueError:
                print( "Not a number, Try Again" )
            else:
                if 10 < p < 100:    # this is much faster than your approach
                    break           # exit the loop
                else: 
                    print( "Value not in range")
    
                    # increment counter to exit when 2 tries are over
                    exit_counter+=1
                    if ( counter > 2 ):
                        print( "Good Bye" )
                        sys.exit(0)  # bye()
    
         return p
    
Pacific Stickler
  • 1,078
  • 8
  • 20