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")