Came across try/except blocks, such as:
def foo(name):
try:
if name == "bad_name":
raise Exception()
except Exception:
do_something()
return
Is there a reason for doing this, instead of:
def foo(name):
if name == "bad_name":
do_something()
return
In your example specific I would also not have used try/except because as you stated, you could just use an if statement.
Try/except is for occasions where you know the program may crash, so therefore you have written some code that'll run instead of the entire program crashing. You could for example override the default error messages with custom ones.
A better example could be that you want to multiply a number the user wrote times two. Since the input function always returns a string, we need to cast it to an int using the built-in int function. This would work fine if the user had typed in an integer, but if the user had typed in a str instead, the entire program would crash. Let's say we want to print out a message if that happens, we could use try/except. If we also want to repeat the question over and over again until the user writes an integer, we can use a simple while loop. The code below is an implementation of this.
print("Write any integer and I will multiply it with two!")
while True:
# Get user input
userInput = input("Write any number: ")
try:
# Here we try to cast str to int
num = int(userInput)
# The next line will only be run if the line before
# didn't crash. We break out of the while loop
break
# If the casting didn't work, this code will run
# Notice that we store the exception as e,
# so if we want we could print it
except Exception as e:
print("{} is not an integer!\n".format(userInput))
# This code will be run if the while loop
# is broken out of, which will only happen
# if the user wrote an integer
print("Your number multiplied with 2:\n{}".format(num * 2))
Expected outcome:
Write any integer and I will multiply it with two!
Write any number: a
a is not an integer!
Write any number: b
b is not an integer!
Write any number: 4
Your number multiplied with 2:
8
Related
I'm trying to make a quick and simple function to check if an entered value is an int/bool. I've had a quick look around and even the solution elsewhere comes to the same issue.
I have this in my test script and it seems to work, but when copying the exact code to my main program it will return the first value entered (say I entered hello instead of a number it will exit with "hello" after typing a number and save that to file).
Is there something with a function calling another function that causes it to fail?
I can post my actual code later, there's a lot of calls in it so it may be quite long. Will try with these short examples first and if we can't figure I can post the long one.
#option 1
import json
with open("settings.json", "r") as f:
pref_file = json.load(f)
def float_check(t):
if t.isdigit():
global prompt
prompt = float(t)
return #I have tried 'return prompt' too
else:
prompt = input ("Enter numerical value only:\n")
float_check(prompt)
prompt = input ("Enter a number: ")
float_check(prompt)
#I'm saving the value to JSON file.
#\\ settings.json
#{
# "o2_percent": 0.0
#}
pref_file["o2_percent"] = prompt
with open("settings.json", "w") as f:
json.dump(pref_file, f, indent=4)
In option 2 I tried calling a function from a function as I thought that was the issue. But this also seems to work.
#option 2
import json
def num_check(t):
if t.isdigit():
global prompt
prompt = float(t)
pref_file["o2_percent"] = prompt
with open("settings.json", "w") as f:
json.dump(pref_file, f, indent=4)
runit()
else:
prompt = input ("Enter numerical numer only:\n")
num_check(prompt)
def runit():
prompt = input ("enter a number: ")
num_check(prompt)
runit()
I found this solution (How to validate a users input to Numbers only?) and have adapted it a little but I'm having the exact same issue - my main code will return the first value entered not the number when exiting the loop.
enter number: hello
enter number: elephant
enter number: why
enter number: 5
saves value to settings.json "hello"
Also why does the first print return float as expected but the second is an str, I've done no further processing? I'm new to all this - is there some jenky thing if using variables in a function even if declared global?
def mk_float(answer):
while True:
try:
answer = float(answer)
print (type(answer)) #returns float
break
except ValueError:
answer = input ("Enter number!")
answer = input ("number: ")
mk_float(answer)
print (type(answer)) #returns int
I'm about ready to table flip.
Edit
This was my comment that I deleted, as Prune pointed out its a seperate question. But will throw it on the edit so people know what it was in reference to.
def t_check(prompt):
while True:
try:
prompt = int(prompt)
return int(prompt)
break
except ValueError:
prompt = input ("Enter a number only: ")
continue
prompt = input ("enter something: ")
t_check(prompt)
print (prompt)
print (type(prompt))
The surface problem is because, when you repeat the request for valid input, instead of using a simple loop-until-valid approach, you use recursion. As you wind back up the stack on final return, you can easily get a reversal of the data you want.
The next problem is using global variables. Use parameters for input to your function; return the result. Global variables usually indicate poor design.
Note that print returns None, not a float.
Finally, you should trace your program's execution, as well as intermediate results, using simple print commands. This is the simplest and most immediately effective debugging tool.
Does that help you get going?
I am not sure I can help with the json part of your code, however you may use this function to ask the user to input a number (float or int) :
def input_number():
try:
return float(input ("Enter numerical value only:\n"))
except ValueError:
return input_number()
When the user input something, input_number will try to return the input as a float (which cover the int type).
If the conversion to float fails, a ValueError will be catch and input_number will ask the user to enter the value again.
In your very specific case you may do pref_file["o2_percent"] = input_number()
Edit:
Looking at Prune's answer, recursion might not be the best good solution. ^_^
def main():
prompt = input('How many players? ')
if prompt.isdigit():
num_players = int(prompt)
else:
print('Invalid input!')
main()
print(num_players)
main()
If I enter a valid integer from the first time, everything works as expected, but if I enter a string first, the 'else' executes and I get prompted again, However, I get the UnboundLocalError when I actually input an integer. Any help is appreciated
The problem is because this function is recursive. When you correctly enter an integer the second time, the innermost instance of main returns to the outer instance of main just after your else block. The next thing it tries to do is print(num_players) which worked fine in the inner instance but is unbound in the outer one.
Try moving the print inside the if
Note, it's not really the recursion that's the issue, it will still error if you remove the recursive call to main . The recursion just means you don't see the error until you finally enter an integer
You shouldn't be using recursion for this at all.
def main():
while True:
prompt = input('How many players? ')
if prompt.isdigit():
break
print('Invalid input!')
print(num_players)
There's no reason to use isdigit and int; you never use the int value, as it is immediately turned into a str again by print.
You can, however, use int instead of isdigit (especially if plan to use the int value later, rather than just printing it.
def main():
while True:
prompt = input('How many players? ')
try:
num_players = int(prompt)
break
except ValueError:
pass
print(num_players)
Hello guys is there any differences between print my output in "try" clause or putting it after "except" clause with "else:"?
here is the code:
try:
Value1 = int(input("Type the first number: "))
Value2 = int(input("Type the second number: "))
Output = Value1 / Value2
except ZeroDivisionError:
print("Attempted to divide by zero!")
else:
print(Output)
or this?
try:
Value1 = int(input("Type the first number: "))
Value2 = int(input("Type the second number: "))
Output = Value1 / Value2
print(Output)
except ZeroDivisionError:
print("Attempted to divide by zero!")
I mean which one is better? because the result is same.
Thanks.
Like you already know we are talking about error handling when we are using try...except.
When an error is generated by an operation (or other statements) Python will stop the try block execution and is passed down to the first except block that matches the raised exception.
In case there isn't an except clause that matches our exception, it is passed on the outer try statement. This until it's handled or no handler is found, the raised exception becomes an unhandled exception and execution stops with a message of the error traceback.
In addition to except block we can use a finally block, that will be executed regardless of whether an exception occurs, and else block. The last one is useful for code that must be executed if the try clause does not raise an exception.
Your examples
How you said this two pieces of code gives the same result. However, with we read on documentation page of Python we have this affirmation:
"The use of the else clause is better than adding additional code to the try clause because it avoids accidentally catching an exception that wasn’t raised by the code being protected by the try … except statement."
Simple speaking if you have different statements that raises the same error, but for one them you aren't interested in catching it, move it to else clause. Look on this question on stack to understand better.
So in your case you can let print statement in try block because you will not catch some particular exceptions from it and there isn't much difference in this case where you put the print statement. However, I think the second example is a good logic separation of type "If no errors where founded then let's execute print".
The else clause is run only when no exception is thrown.
So the reason why you'd want to put it in there is to make it explicit: you only want to print the output if there was no exception.
As you mentioned, in your code, there's no functional difference to what happens.
See the docs for more information.
The first one will work fine as per your expectations (assuming that you don't want to bring up the python error prompt and halt the program).
It simply prescribes that IF 2nd digit is zero then it won't print the Python error prompt and pass it to the print command (And that's how it should be). Otherwise, in every other case, no matter whatever the divisor is, it will always give an output, so that way you eliminate nearly all loopholes.
Suggestion:
Keep the input type as float instead of int, that way you'll be able to print the division for decimal numbers input also. Ex-2/3
SO for my project in python, I am taking two inputs say a & b as integer values. Now the code goes like:
import sys
a = input("enter a")
b = input("enter b")
if a < b:
print(" enter a greater than b and try again")
sys.exit()
# Rest of the code is here
Now this works fine. But creates an extra statement
An exception has occurred, use %tb to see the full traceback.
SystemExit
And I do not want that as the user may think that the code's functioning is not proper. So is there any way that this statement is not shown or any other function which would exit the code without printing anything except the line which I have written?
NOTE I have tried exit() but it continues to execute the code beneath it. Also, I have noticed this related question but the approaches listed there don't work in this case.
EDIT: I am adding some more information. I need to put this exit function into a user-defined function so that every time the user enters some wrong data, the code will call this user-defined function and will exit the code.
If I try to put my code in an if else statement like
def end():
print("incorrect input try again")
os.exit()
a = input("enter data")
if a < 10:
end()
b = input ("enter data")
if b < 20:
end()
# more code here
I don't know why but I can't even define this user-defined function in the end as it raises the error of undefined function end(). I'm using Python with Spyder on Windows.
You can use os._exit()
a = int(input("enter a"))
b = int(input("enter b"))
if a < b:
print(" enter a greater than b and try again")
os._exit(0)
This seems to work just fine:
import sys
def end():
print("incorrect input try again")
sys.exit(1)
a = input("enter data")
if int(a) < 10:
end()
b = input ("enter data")
if int(b) < 20:
end()
I used the sys.exit and fixed your conditions to avoid comparing string with integers. I cannot see any additional messages in the output. Only this:
>py -3 test2.py
enter data1
incorrect input try again
>
Please also take notice of this qoute from python docs:
The standard way to exit is sys.exit(n). [os]_exit() should normally only
be used in the child process after a fork().
It also works in the repl
I am learning Exception in python and i have some doubt:
Can we use any name as error in raise?
like i have read when you use raise you have to define error type so can't i use any stringname as Error? like SkienaError or i have to keep in mind all the error types and have to use only those Error type names ?
a=int(input())
if a!=10:
raise SkienaError
else:
print(a,"pp")
Second doubt is suppose i want user should input int but he input string so an assert pop up but i want program should continue without terminate and again ask for input until user give int type input , I don't want to use while loop here i want to know if it is possible with raise or assert in python ? like:
a=int(input())
assert type(a)==int
print(a,"hello")
So if user give str type input then is it possible program keep giving error and asking new input until input type is int.
In order to make your own exception, you'll have to create it.
e.g.
class MyAppLookupError(LookupError):
'''raise this when there's a lookup error for my app'''
To continue execution after a thrown Exception, do it like this:
a = 5
try:
assert a == 5
except AssertionError as e:
print(e)
A try block will attempt to execute a block of code. If an exception occurs, it will execute the except block.
This might also work for your situation. The function Assert() prints a message sTxt in red color, if the Boolean input bCond is False and interpreter continues execution:
RED, END = '\033[91m', '\033[0m'
printRed = lambda sTxt: print(RED + sTxt + END)
Assert = lambda bCond=False, sTxt='': printRed(sTxt) if not bCond else None