How to catch exception for multiple validation in a single try block ? Is it possible or do I need to use multiple try block for that ? Here is my code :
import sys
def math_func(num1, num2):
return num1*num2
a,b = map(str,sys.stdin.readline().split(' '))
try:
a = int(a)
b = int(b)
print("Result is - ", math_func(a,b), "\n")
except FirstException: # For A
print("A is not an int!")
except SecondException: # For B
print("B is not an int!")
Python believes in explicit Exception handling. If your intention is to only know which line causes the exception then don't go for multiple exception. In your case you don't need separate Exception handlers, since you are not doing any conditional operation based on the specific line raising an exception.
import sys
import traceback
def math_func(num1, num2):
return num1*num2
a,b = map(str, sys.stdin.readline().split(' '))
try:
a = int(a)
b = int(b)
print("Result is - ", math_func(a,b), "\n")
except ValueError:
print(traceback.format_exc())
This will print which line cause the error
You can indeed catch two exceptions in a single block, this can be done like so:
import sys
def mathFunc(No1,No2):
return No1*No2
a,b = map(str,sys.stdin.readline().split(' '))
try:
a = int(a)
b = int(b)
print("Result is - ",mathFunc(a,b),"\n")
except (FirstException, SecondException) as e:
if(isinstance(e, FirstException)):
# put logic for a here
elif(isinstance(e, SecondException)):
# put logic for be here
# ... repeat for more exceptions
You can also simply catch a generic Exception, this is handy for when program excecution must be maintained during runtime, but it is best practice to avoidthis and catch the specific exceptions instead
Hope this helps!
Possibly a duplicate of this?
Related
I have a small program which calls multiple functions from the main() function and in each of the functions there is a small probability, that an error occurs. In order to be compatible with the existing monitoring system, I need to make a file to /var/tmp/error_triggered/ directory if there was at least one error or remove the file from this directory if there were no errors. One way to do this is to use variable with global scope:
#!/usr/bin/env python3
import os
import random
from pathlib import Path
def f1():
global error
for i in range(1, 5):
if random.randint(0, 9) == 0:
error = 1
def f2():
global error
for i in range(1, 5):
if random.randint(0, 9) == 0:
error = 1
def main():
f1()
f2()
if __name__ == '__main__':
error = 0
main()
if error == 1:
Path('/var/tmp/error_triggered/' + os.path.splitext(os.path.basename(__file__))[0]).touch()
else:
Path('/var/tmp/error_triggered/' + os.path.splitext(os.path.basename(__file__))[0]).unlink(missing_ok=True)
It is usually a bad practice to modify a global variable from inside functions. Is it justified here? Or is there a better approach to solve this problem?
The standard way of handling errors in Python is raising exceptions:
def f1():
for i in range(1, 5):
if random.randint(0, 9) == 0:
raise ValueError()
def f2():
for i in range(1, 5):
if random.randint(0, 9) == 0:
raise ValueError()
def main():
f = Path('/var/tmp/error_triggered/' + os.path.splitext(os.path.basename(__file__))[0])
try:
f1()
f2()
f.unlink(missing_ok=True)
except ValueError:
f.touch()
There's a subtle difference between this and what you were doing: if f1 raises an exception, f2 won't be called (that is, raising an exception immediately stops the try block and goes straight to the except). This is desirable behavior more often than not, since usually if an error happens you don't want to keep going with what you were doing.
If for some reason you want f2 to be called even if f1 has already produced an error, then it might be more appropriate to return the error the same way you'd return any other value:
def f1():
for i in range(1, 5):
if random.randint(0, 9) == 0:
return 1
return 0
def f2():
for i in range(1, 5):
if random.randint(0, 9) == 0:
return 1
return 0
def main():
f = Path('/var/tmp/error_triggered/' + os.path.splitext(os.path.basename(__file__))[0])
if f1() + f2():
f.touch()
else:
f.unlink(missing_ok=True)
Using a global is almost never the best way to pass information between functions. For anything beyond the simplest cases it will just make your code very difficult to debug.
I'd suggest creating an ERROR_COUNTER int variable or dictionary which stores the counts, something like:
{ functionname: count, functionname2: count }
Which is updated with every occurence of an error.
Making variables global from inside functions is not great.
I don't know your use case/context specifically but you could also return an int of errors with each function call if all they do is perform an action. This would make the caller responsible for handling the count of errors than individual functions.
I'd echo what some of the others have raised here, that raising exceptions is the appropriate response to errors but add that embedding a try/except loop if you need specific error behaviour:
def a():
if random.randint(0, 9) == 0:
raise Exception("error!")
def main():
f = Path('/var/tmp/error_triggered/' + os.path.splitext(os.path.basename(__file__))[0])
try:
for i in range(0,5):
a()
f.unlink(missing_ok=True)
except Exception as e:
print(e)
f.touch()
I'm assuming your code is a bit more complicated that raising errors at random, but the principles the same- if something hits and error, it should raise an exception, if you need to handle the exception in a way that isn't just leaving the shell, use a try/except loop.
I am stuck with a Python issue related to threading.
import threading
import time
import random
import sys
import echo
class presence(threading.Thread):
def __init__(self, cb):
threading.Thread.__init__(self)
self.callback = cb
def run(self):
minValue = 0
maxValue = 3
try:
while True:
time.sleep(1)
if random.randint(minValue, maxValue) == 1:
self.callback(1)
elif random.randint(minValue, maxValue) == 2:
raise Exception('An error')
else:
self.callback(0)
except:
print 'Exception caught!'
pass
def showAlert():
echo.echo('Someone is behind the door!')
def count(x):
if x == 1:
showAlert()
sys.stdout.flush()
That is how I call it:
t2 = presence.presence(presence.count)
t2.start()
I eventually get an "Exception caught!", but the thread stops not returning alerts anymore.
What did I do wrong here?
The try/except block should be inside the loop. For example:
while True:
...
elif random.randint(minValue, maxValue) == 2:
try:
raise Exception('An error')
except Exception:
print 'Exception caught!'
Otherwise, the loop will be exited when the exception is raised and Python jumps to the except: block in order to handle it.
You'll notice too that I selectively placed the try/except block in my example to only cover the code that might actually raise the exception. This is a best practice and I recommend it for your code. Having a try/except block enclose large portions of code decreases readability and also wastes space (lots of lines are unnecessarily indented).
Can I return to executing the try block after exception occurs?
For example:
try:
do_smth1()
except:
pass
try:
do_smth2()
except:
pass
vs.
try:
do_smth1()
do_smth2()
except:
??? # magic word to proceed to do_smth2() if there was exception in do_smth1
No, you cannot do that. That's just the way Python has its syntax. Once you exit a try-block because of an exception, there is no way back in.
What about a for-loop though?
funcs = do_smth1, do_smth2
for func in funcs:
try:
func()
except Exception:
pass # or you could use 'continue'
Note however that it is considered a bad practice to have a bare except. You should catch for a specific exception instead. I captured for Exception because that's as good as I can do without knowing what exceptions the methods might throw.
While the other answers and the accepted one are correct and should be followed in real code, just for completeness and humor, you can try the fuckitpy ( https://github.com/ajalt/fuckitpy ) module.
Your code can be changed to the following:
#fuckitpy
def myfunc():
do_smth1()
do_smth2()
Then calling myfunc() would call do_smth2() even if there is an exception in do_smth1())
Note: Please do not try it in any real code, it is blasphemy
You can achieve what you want, but with a different syntax. You can use a "finally" block after the try/except. Doing this way, python will execute the block of code regardless the exception was thrown, or not.
Like this:
try:
do_smth1()
except:
pass
finally:
do_smth2()
But, if you want to execute do_smth2() only if the exception was not thrown, use a "else" block:
try:
do_smth1()
except:
pass
else:
do_smth2()
You can mix them too, in a try/except/else/finally clause.
Have fun!
'continue' is allowed within an 'except' or 'finally' only if the try block is in a loop. 'continue' will cause the next iteration of the loop to start.
So you can try put your two or more functions in a list and use loop to call your function.
Like this:
funcs = [f,g]
for func in funcs:
try: func()
except: continue
For full information you can go to this link
You could iterate through your methods...
for m in [do_smth1, do_smth2]:
try:
m()
except:
pass
one way you could handle this is with a generator. Instead of calling the function, yield it; then whatever is consuming the generator can send the result of calling it back into the generator, or a sentinel if the generator failed: The trampoline that accomplishes the above might look like so:
def consume_exceptions(gen):
action = next(gen)
while True:
try:
result = action()
except Exception:
# if the action fails, send a sentinel
result = None
try:
action = gen.send(result)
except StopIteration:
# if the generator is all used up, result is the return value.
return result
a generator that would be compatible with this would look like this:
def do_smth1():
1 / 0
def do_smth2():
print "YAY"
def do_many_things():
a = yield do_smth1
b = yield do_smth2
yield "Done"
>>> consume_exceptions(do_many_things())
YAY
Note that do_many_things() does not call do_smth*, it just yields them, and consume_exceptions calls them on its behalf
I don't think you want to do this. The correct way to use a try statement in general is as precisely as possible. I think it would be better to do:
try:
do_smth1()
except Stmnh1Exception:
# handle Stmnh1Exception
try:
do_smth2()
except Stmnh2Exception:
# handle Stmnh2Exception
Depending on where and how often you need to do this, you could also write a function that does it for you:
def live_dangerously(fn, *args, **kw):
try:
return fn(*args, **kw)
except Exception:
pass
live_dangerously(do_smth1)
live_dangerously(do_smth2)
But as other answers have noted, having a null except is generally a sign something else is wrong with your code.
This can be done with exec() in a custom function, a list of strings, and a for loop.
The function with exec():
def try_it(string):
try:
exec(string)
print(f'Done: {string}')
except:
print(f'Error. Could not do: {string}')
More on exec():
exec(object)
This function supports dynamic execution of Python code. object must be either a string or a code object.
Example list of strings and for loop:
do_smth_list = ['do_smth1()', 'do_smth2()', 'do_smth3()']
for smth in do_smth_list:
try_it(smth)
This definitely isn't the cleanest way of doing it, but you can put it in a while loop with a variable set to true, and when it runs the function successfully it sets the variable to false, whereas if it fails it keeps the variable set to true.
x = True
while x == True:
try:
do_smth1()
do_smth2()
x = False
except Exception:
x = True
This way what happens is that the while loop will keep on looping the try except section again and again until it works, in which x is set to false and the loop stops
Also, you can implement a break in the while loop instead of basing it on a variable, for example:
while True:
try:
do_smth1()
do_smth2()
break
except Excpetion:
pass
P.S It is good ettiquete to put a specific exception for the except section, instead of leaving it for any exception. It makes the code cleaner and is more sensible when managing errors especially in bigger projects
special_func to avoid try-except repetition:
def special_func(test_case_dict):
final_dict = {}
exception_dict = {}
def try_except_avoider(test_case_dict):
try:
for k,v in test_case_dict.items():
final_dict[k]=eval(v) #If no exception evaluate the function and add it to final_dict
except Exception as e:
exception_dict[k]=e #extract exception
test_case_dict.pop(k)
try_except_avoider(test_case_dict) #recursive function to handle remaining functions
finally: #cleanup
final_dict.update(exception_dict)
return final_dict #combine exception dict and final dict
return try_except_avoider(test_case_dict)
Run code:
def add(a,b):
return (a+b)
def sub(a,b):
return (a-b)
def mul(a,b):
return (a*b)
case = {"AddFunc":"add(8,8)","SubFunc":"sub(p,5)","MulFunc":"mul(9,6)"}
solution = special_func(case)
Output looks like:
{'AddFunc': 16, 'MulFunc': 54, 'SubFunc': NameError("name 'p' is not defined")}
To convert to variables:
locals().update(solution)
Variables would look like:
AddFunc = 16, MulFunc = 54, SubFunc = NameError("name 'p' is not defined")
If do_smth1() worked, then do_smth2() will not be tried.
try:
x=do_smth1()
except:
try:
x=do_smth2()
except:
x="Both Failed"
print (x)
How can I get the name of an exception that was raised in Python?
e.g.,
try:
foo = bar
except Exception as exception:
name_of_exception = ???
assert name_of_exception == 'NameError'
print "Failed with exception [%s]" % name_of_exception
For example, I am catching multiple (or all) exceptions, and want to print the name of the exception in an error message.
Here are a few different ways to get the name of the class of the exception:
type(exception).__name__
exception.__class__.__name__
exception.__class__.__qualname__
e.g.,
try:
foo = bar
except Exception as exception:
assert type(exception).__name__ == 'NameError'
assert exception.__class__.__name__ == 'NameError'
assert exception.__class__.__qualname__ == 'NameError'
If you want the fully qualified class name (e.g. sqlalchemy.exc.IntegrityError instead of just IntegrityError), you can use the function below, which I took from MB's awesome answer to another question (I just renamed some variables to suit my tastes):
def get_full_class_name(obj):
module = obj.__class__.__module__
if module is None or module == str.__class__.__module__:
return obj.__class__.__name__
return module + '.' + obj.__class__.__name__
Example:
try:
# <do something with sqlalchemy that angers the database>
except sqlalchemy.exc.SQLAlchemyError as e:
print(get_full_class_name(e))
# sqlalchemy.exc.IntegrityError
You can print the exception using some formated strings:
Example:
try:
#Code to execute
except Exception as err:
print(f"{type(err).__name__} was raised: {err}")
You can also use sys.exc_info(). exc_info() returns 3 values: type, value, traceback. On documentation: https://docs.python.org/3/library/sys.html#sys.exc_info
import sys
try:
foo = bar
except Exception:
exc_type, value, traceback = sys.exc_info()
assert exc_type.__name__ == 'NameError'
print "Failed with exception [%s]" % exc_type.__name__
This works, but it seems like there must be an easier, more direct way?
try:
foo = bar
except Exception as exception:
assert repr(exception) == '''NameError("name 'bar' is not defined",)'''
name = repr(exception).split('(')[0]
assert name == 'NameError'
The other answers here are great for exploration purposes, but if the primary goal is to log the exception (including the name of the exception), perhaps consider using logging.exception instead of print?
Is it reasonable in Python to catch a generic exception, then use isinstance() to detect the specific type of exception in order to handle it appropriately?
I'm playing around with the dnspython toolkit at the moment, which has a range of exceptions for things like a timeout, an NXDOMAIN response, etc. These exceptions are subclasses of dns.exception.DNSException, so I am wondering if it's reasonable, or pythonic, to catch DNSException then check for a specific exception with isinstance().
e.g.
try:
answers = dns.resolver.query(args.host)
except dns.exception.DNSException as e:
if isinstance(e, dns.resolver.NXDOMAIN):
print "No such domain %s" % args.host
elif isinstance(e, dns.resolver.Timeout):
print "Timed out while resolving %s" % args.host
else:
print "Unhandled exception"
I'm new to Python so be gentle!
That's what multiple except clauses are for:
try:
answers = dns.resolver.query(args.host)
except dns.resolver.NXDOMAIN:
print "No such domain %s" % args.host
except dns.resolver.Timeout:
print "Timed out while resolving %s" % args.host
except dns.exception.DNSException:
print "Unhandled exception"
Be careful about the order of the clauses: The first matching clause will be taken, so move the check for the superclass to the end.
From dns.resolver you can import some exceptions.
(untested code)
from dns.resolver import Resolver, NXDOMAIN, NoNameservers, Timeout, NoAnswer
try
host_record = self.resolver.query(self.host, "A")
if len(host_record) > 0:
Mylist['ERROR'] = False
# Do something
except NXDOMAIN:
Mylist['ERROR'] = True
Mylist['ERRORTYPE'] = NXDOMAIN
except NoNameservers:
Mylist['ERROR'] = True
Mylist['ERRORTYPE'] = NoNameservers
except Timeout:
Mylist['ERROR'] = True
Mylist['ERRORTYPE'] = Timeout
except NameError:
Mylist['ERROR'] = True
Mylist['ERRORTYPE'] = NameError