Python Forum
How to make the function to prompt the user repeatedly till he enters a no - Printable Version

+- Python Forum (https://python-forum.io)
+-- Forum: Python Coding (https://python-forum.io/forum-7.html)
+--- Forum: Homework (https://python-forum.io/forum-9.html)
+--- Thread: How to make the function to prompt the user repeatedly till he enters a no (/thread-24458.html)



How to make the function to prompt the user repeatedly till he enters a no - sbabu - Feb-15-2020

def ck_no(prompt):
    while True:
        try:
            
            lst = (2,3,4)
            if prompt not in lst:
                print("not in list")
                raise ValueError
            else:
                print("In the List")
        except ValueError as e:
            print(e)
            return
            
ck_no(int(input(print("Enter a No: "))))
Output:
Enter a No: None
After calling the function it prompts the user to enter the no. But it prints none. Beside none if enter the no it accepts and the pgm continues. How to correct this none.

I want to prompt the user again and again to enter different nos. How to do this?

Thanks


RE: How to make the function to prompt the user repeatedly till he enters a no - michael1789 - Feb-15-2020

You're facing a number of problems here. For one, the "None" is because your function isn't returning any information. Also you don't use "print" in a input statement, it is implied by the input().

If it is an assignment or something that requires your to use try then this won't work, but it's an overall simpler approach.

def ck_no():

    lst = (2,3,4)
    
    while True:
        prompt = int(input("Enter a No: "))
        if prompt not in lst:
            print("not in list")
        
        else:
            print("In the List")
            break
        
             
ck_no()



RE: How to make the function to prompt the user repeatedly till he enters a no - DeaD_EyE - Feb-15-2020

Error:
ValueError: invalid literal for int() with base 10: 'd'
If a user enters a str which could not cast to an int, then you get a ValueError.

def ck_no():
    """
    Ask for user input of a valid number and repeat the
    question, if the user enters a number, which is not
    allowed or an invalid number.

    Allowed numbers: 2, 3, 4

    Return value of the valid answer as int.
    """
    valid_choice = (2, 3, 4)  # Pep8, always a white space after the comma
    # better names helps other people to understand
    # the code
    while True:
        answer = input("Enter a No: ")
        # get the answer
        # we need this for later output if
        # there was an exception while casting to an int
        try:
            value = int(answer)
            # here a ValueError occurs if answer is an integer  
        except ValueError:
            print("Invalid input:", answer)
            # catch this exception
            # print the error
            # don't do further checks, continue on the top
            # of the loop
            # so, the rest is skipped
            continue
        # this point is reached, if no ValueError happens
        if value in valid_choice:
            # simple check if a value is in a sqeuence or collection
            # return the value, if the value was in the list
            # the value is an int
            return value
        # if value was not in valid_choice, the if-block is not executed
        # no return, so this line of code is reached
        print("Value", value, "is not a valid choice")
        # just print that the value was not in the tuple

ck_no()
You can generalize this function, if you make
  • question as argument of the function and use this, instead of the hard-coded str for input.
  • valid_choice as argument

def general_ck_no(question, valid_choice):
    ...


For exception handling is always the question, if the caller should handle the error or the called function.

In this case the called function ck_no is doing the exception handling and return only int, which are in valid_choice.

If you put something in valid_choice, which is not an int, you can't use it, because the cast to an int will fail. The output from input is always str.



If you just use a plain return, the function will return None.
The compiler adds always an implicit return None to the function.

This function return None:
def foo():
    1 + 1
This function return "even" if the value was even and None if the value was odd.
def foo(value):
    if value % 2 == 0:
        return "even"
This function return "even" or "odd".
There is no other possibility. Only the first code block of the if statement is used or the other block.
There is no other if-branch in the function, which could leave the function without an explicit return.

def foo(value):
    if value % 2 == 0:
        return "even"
    else:
        return "odd"
Functions, which return always the same type are easier to handle.
Situations, where the input was invalid, should handled by exception handling and not return None.
The point is, when you check a value for truthiness, following rules are applied:
  • bool(None) == False
  • bool(0) == False
  • bool(1) == True
  • bool(-1) == True
  • bool([]) == False # empty list
  • bool([1]) == True # not empty list
  • collections (dict, set, frozenset, ...) and sequences (tuple, list, deque, ...) are True if you do the truthiness and they are not empty.

value = 42

if bool(value):
    print("Value is not 0")
else:
    print("Value is 0")
is the same as


value = 42

if value:
    print("Value is not 0")
else:
    print("Value is 0")
Now think about it, if you have to distinguish between None, 0 and all other integers.
The object None is unique and exists only once in memory, so you can do the identity check.

value = None

if value is None:
    print("value is None")
But don't do this for scalar types like int, float etc.
value = 1337

# is always False, because value points to another 1337 in memory
if value is 1337: # <- this 1337 has a different identity as the name value points to
    print("value is 1337")
Since Python 3.8 beginners get better warnings. Using this code, result into this warning:
Error:
<>:4: SyntaxWarning: "is" with a literal. Did you mean "=="?

Correct is:
value = 1337

if value == 1337:
    print("value is 1337")



RE: How to make the function to prompt the user repeatedly till he enters a no - Blackdog31 - Mar-26-2020

Just a question. If the value is valid, how do we print the entered value?

After the return value?

Example: if value = 2, print (“Value is 2”)
if value = 3, print (“Value is 3”)



(Feb-15-2020, 09:17 AM)DeaD_EyE Wrote:
Error:
ValueError: invalid literal for int() with base 10: 'd'
If a user enters a str which could not cast to an int, then you get a ValueError.

def ck_no():
    """
    Ask for user input of a valid number and repeat the
    question, if the user enters a number, which is not
    allowed or an invalid number.

    Allowed numbers: 2, 3, 4

    Return value of the valid answer as int.
    """
    valid_choice = (2, 3, 4)  # Pep8, always a white space after the comma
    # better names helps other people to understand
    # the code
    while True:
        answer = input("Enter a No: ")
        # get the answer
        # we need this for later output if
        # there was an exception while casting to an int
        try:
            value = int(answer)
            # here a ValueError occurs if answer is an integer  
        except ValueError:
            print("Invalid input:", answer)
            # catch this exception
            # print the error
            # don't do further checks, continue on the top
            # of the loop
            # so, the rest is skipped
            continue
        # this point is reached, if no ValueError happens
        if value in valid_choice:
            # simple check if a value is in a sqeuence or collection
            # return the value, if the value was in the list
            # the value is an int
            return value
        # if value was not in valid_choice, the if-block is not executed
        # no return, so this line of code is reached
        print("Value", value, "is not a valid choice")
        # just print that the value was not in the tuple

ck_no()
You can generalize this function, if you make
  • question as argument of the function and use this, instead of the hard-coded str for input.
  • valid_choice as argument

def general_ck_no(question, valid_choice):
    ...


For exception handling is always the question, if the caller should handle the error or the called function.

In this case the called function ck_no is doing the exception handling and return only int, which are in valid_choice.

If you put something in valid_choice, which is not an int, you can't use it, because the cast to an int will fail. The output from input is always str.



If you just use a plain return, the function will return None.
The compiler adds always an implicit return None to the function.

This function return None:
def foo():
    1 + 1
This function return "even" if the value was even and None if the value was odd.
def foo(value):
    if value % 2 == 0:
        return "even"
This function return "even" or "odd".
There is no other possibility. Only the first code block of the if statement is used or the other block.
There is no other if-branch in the function, which could leave the function without an explicit return.

def foo(value):
    if value % 2 == 0:
        return "even"
    else:
        return "odd"
Functions, which return always the same type are easier to handle.
Situations, where the input was invalid, should handled by exception handling and not return None.
The point is, when you check a value for truthiness, following rules are applied:
  • bool(None) == False
  • bool(0) == False
  • bool(1) == True
  • bool(-1) == True
  • bool([]) == False # empty list
  • bool([1]) == True # not empty list
  • collections (dict, set, frozenset, ...) and sequences (tuple, list, deque, ...) are True if you do the truthiness and they are not empty.

value = 42

if bool(value):
    print("Value is not 0")
else:
    print("Value is 0")
is the same as


value = 42

if value:
    print("Value is not 0")
else:
    print("Value is 0")
Now think about it, if you have to distinguish between None, 0 and all other integers.
The object None is unique and exists only once in memory, so you can do the identity check.

value = None

if value is None:
    print("value is None")
But don't do this for scalar types like int, float etc.
value = 1337

# is always False, because value points to another 1337 in memory
if value is 1337: # <- this 1337 has a different identity as the name value points to
    print("value is 1337")
Since Python 3.8 beginners get better warnings. Using this code, result into this warning:
Error:
<>:4: SyntaxWarning: "is" with a literal. Did you mean "=="?

Correct is:
value = 1337

if value == 1337:
    print("value is 1337")