- writing multiple try and except in python
- 3 Answers 3
- python catch several exceptions
- 4 Answers 4
- When is catching exceptions explicitly a failure
- How to Catch Multiple Exceptions in Python
- Using Same Code Block for Multiple Exceptions
- Using Different Code Blocks for Multiple Exceptions
- Investigating Exceptions using If, Elif, Else Statements
- Multiple Except Clauses Matching
- Track, Analyze and Manage Errors With Rollbar
- Related Resources
- How to handle multiple exceptions?
- 3 Answers 3
writing multiple try and except in python
I want to know what is the most elegant way of writing try .. except statements in python. Assume I have this code:
with open(sys.argv[1]) as f: for line in f: try: do_1(line) except: pass try: do_2(line) except: pass try: do_3(line) except: pass . .
What is the best way of writing this? My actions are sequential. However, if do_1 fails I still want to perform do_2 . If all of them are in one try .. except block, then if do_1 fails, I will never reach do_2 . Is this the right way, or can I have one except for all of d0_i actions?
You don’t say anything about what’s inside the do_X functions, so I’m going out on a limb here, but I have a feeling that maybe exceptions are not right in the first place. The pattern seems to be that you’re trying several operations on each line (some kind of pattern matching?) and if there’s an exception it’s just swallowed anyway. Maybe use of return values could be a good choice? Exceptions are slow, so to write code where multiple exceptions are expected in a tight loop would result in slow code. Of course I don’t know the details of the code, so I might be wrong for your case.
3 Answers 3
It’s simple enough to write this as a loop:
for action in [do_1, do_2, do_3, . ]: try: action(line) except AppropriateExceptionType: pass
I would factor out the common code which is your try/except statements. Something like:
def run_safely(f, *args): try: f(*args) except SpecificException: # handle appropriately here pass with open(sys.argv[1]) as f: for line in f: run_safely(do_1, line) run_safely(do_2, line) run_safely(do_3, line)
One nitpick: The exception handling causes run_safely to need to operate at more than one level of abstraction at a tim. I.e, the caller of run_safely probably knows more about how to handle the exception than run_safely itself; but the exception is — of necessity — hidden from the caller.
Essentially, you need each do_ function to run inside the finally block of the previous one, like so:
try: do_1(line) except: # Handle failure pass finally: # Run regardless try: do_2(line) except: # Handle failure finally: # Run regardless try: do_3(line) .
This chains the functions together through the finally block. Notice that in the event of an exception at any step, the exception is handled before starting the next step, which is guaranteed to run regardless of whether an exception is generated or not.
Since your functions all have the same shape (taking the same number and type of arguments), you can abstract out this pattern into a function, like tryChain below:
def tryChain(functions, *sharedArgs) f = functions.pop() try: f(*sharedArgs) finally: tryChain(functions) try: tryChain([do_1, do_2, . ], line, arg2, . ) except SpecificException: # Handle exception here, which may be propagated from any of the actions pass
Note that in this case, only the last exception is thrown back to the caller; the others are hidden. (You could handle the exceptions inside tryChain as well, with an except block inserted there; or, you could pass in an error handler for each step; or a map from exception types to the appropriate handler, and re-throw the error if none of them matches — but at that point, you’re practically reinventing exception handling.)
python catch several exceptions
I have some code that is calling several methods from multiple functions. Some of these methods may raise an exception. Each can raise a different type of exception. In my main script, I would like to log the exception and then just exit. So, no matter what the exception type, log it and exit My question is this: is it better to list all the exceptions that might be generated, or just catch a generic Exception? Which is more pythonic? example:
try: some_stuff() except (Exc1, Exc2, Exc3) as exc: loger.exception(exc)
try: some_stuff() except Exception as exc: loger.exception(exc)
Generally it’s much better to be specific with your exceptions, so you can handle them better. In addition, broadly speaking, when a function can’t do what it was intended to, it should terminate.
@kukac But the OP is not planning to handle the exception in any way, apart from logging them into log file. With explicit exceptions you will not be able catching unexpected ones.
4 Answers 4
Your plan to catch exception in main code, log it and terminate is good one.
There could be exceptions, which are fine and do not mean, you shall consider them as problem, e.g. KeyboardInterrupt
- first, catch all the exceptions, which you expect to be fine and pass
- then catch general Exception , log it and terminate.
try: some(stuff) # . # First, resolve expected exceptions except KeyboardInterrupt: pass # Finally, log unexpected ones except Exception as exc: logger.exception(exc) return # time to terminate
When is catching exceptions explicitly a failure
The advice to be better by explicitly catching all expected exceptions comes short in case an unexpected exception happens. Your plan to catch whatever comes to log file sounds good and provide enough information for resolving the problems later on.
Imagine, you have a daemon, which shall run and run. Under some conditions, it might fail.
With only expecting explicit exception, it may happen, unexpected exception happens, no expect would have a chance to log this to a log file, stacktrace would be printed to stdout and forgotten and program terminates.
This is clear and very reasonable use case for catching exception generally.
Because except: catches all exceptions, including SystemExit, KeyboardInterrupt, and GeneratorExit (which is not an error and should not normally be caught by user code), using a bare except: is almost never a good idea. In situations where you need to catch all “normal” errors, such as in a framework that runs callbacks, you can catch the base class for all normal exceptions, Exception. Unfortunately in Python 2.x it is
possible for third-party code to raise exceptions that do not inherit from Exception, so in Python 2.x there are some cases where you may have to use a bare except: and manually > re-raise the exceptions you don’t want to catch.
In general, it is better to catch explicit exceptions. In Python 2, how you are doing it can result in exceptions you still don’t catch if an external module is throwing something that doesn’t inherit exception.
By catching explicit exceptions you are able to handle errors you know can occur. If you catch all, your application could do something unexpected and you may handle it incorrectly.
Additionally, do you really want to catch someone using Ctrl+C to end your program?
How to Catch Multiple Exceptions in Python
When a program encounters an exception during execution, it is terminated if the exception is not handled. By handling multiple exceptions, a program can respond to different exceptions without terminating it.
In Python, try-except blocks can be used to catch and respond to one or multiple exceptions. In cases where a process raises more than one possible exception, they can all be handled using a single except clause.
There are several approaches for handling multiple exceptions in Python, the most common of which are discussed below.
Using Same Code Block for Multiple Exceptions
With this approach, the same code block is executed if any of the listed exceptions occurs. Here’s an example:
try: name = 'Bob' name += 5 except (NameError, TypeError) as error: print(error) rollbar.report_exc_info()
In the above example, the code in the except block will be executed if any of the listed exceptions occurs. Running the above code raises a TypeError , which is handled by the code, producing the following output:
cannot concatenate 'str' and 'int' objects
Using Different Code Blocks for Multiple Exceptions
If some exceptions need to be handled differently, they can be placed in their own except clause:
try: name = 'Bob' name += 5 except NameError as ne: # Code to handle NameError print(ne) rollbar.report_exc_info() except TypeError as te: # Code to handle TypeError print(te) rollbar.report_exc_info()
In the above example, NameError and TypeError are two possible exceptions in the code, which are handled differently in their own except blocks.
Investigating Exceptions using If, Elif, Else Statements
Exceptions can also be checked using if-elif-else conditions, which can be useful if the exception needs to be investigated further:
import errno try: f = open('/opt/tmp/myfile.txt') except IOError as e: rollbar.report_exc_info() if e.errno == errno.ENOENT: print('File not found') elif e.errno == errno.EACCES: print('Permission denied') else: print e
Here, the variable e holds an instance of the raised IOError . The additional status code of the exception is checked in the if , elif and else blocks and the first match is executed:
Multiple Except Clauses Matching
There may be cases where a piece of code causes an exception that can match multiple except clauses:
try: f = open('/opt/tmp/myfile.txt') except EnvironmentError: rollbar.report_exc_info() print('Failed to open file') except IOError: rollbar.report_exc_info() print('File not found')
Since EnvironmentError is more general than IOError , it matches the exception in the code above. The EnvironmentError except clause is listed first, so the code within it gets executed, producing the following output:
Track, Analyze and Manage Errors With Rollbar
Managing errors and exceptions in your code is challenging. It can make deploying production code an unnerving experience. Being able to track, analyze, and manage errors in real-time can help you to proceed with more confidence. Rollbar automates error monitoring and triaging, making fixing Python errors easier than ever. Sign Up Today!
Related Resources
How to Handle Unhashable Type List Exceptions in Python
How to Throw Exceptions in Python
«Rollbar allows us to go from alerting to impact analysis and resolution in a matter of minutes. Without it we would be flying blind.»
How to handle multiple exceptions?
The idea of implementing in this fashion is to catch the exact error for all different scenarios. I can do it in all separate try / except blocks.
Is this possible? And reasonable?
Yes what your doing is correct. For every exception type, just use the specific error you’re going to catch. i.e. except KeyError, ValueError
I take that back, based on your scenario’s, you are much better off creating multiple try catch blocks of code. i.e. def check_file(file): try . except your_ exceptions_here .
Basically the main idea of a try catch block is to do something, not do all, as multiple errors could be encountered along the way.
If what your trying to achieve is something like try: read_file then you could go with except FileNotFound? . except IsNotAFile? . .. but if your doing try: read_file then crunch it then yea, segregate them.
@Eduard Daduya : Multiple try/catch blocks is easy. I thought based on customized exceptions, i can handle single try with multiple exception blocks. Can it be done ?
3 Answers 3
try: # do all except Exception: pass
What you want to be doing is having multiple try/except blocks, each one responsible for as few things as possible and catching the most specific exception.
try: # opening the file except FileNotFoundException: print('File does not exist') exit() try: # writing to file except PermissionError: print('You do not have permission to write to this file') exit()
However, sometimes it is appropriate to catch different types of exceptions, in the same except block or in several blocks.
try: ssh.connect() except (ConnectionRefused, TimeoutError): pass
try: ssh.connect() except ConnectionRefused: pass except TimeoutError: pass
Playing devil’s advocate: didn’t we make the leap from explicit error handling to exceptions that bubble up the stack specifically to get the ability to make larger try blocks and centralize error handling somewhere else?
Your try blocks should be as minimal as possible.
try: # do all except Exception: pass
Then you might as well do something like
def open_file(file): retval = False try: # opening the file succesful? retval = True except FileNotFoundException: print('File does not exist') except PermissionError: print('You have no permission.') return retval def crunch_file(file): retval = False try: # conversion or whatever logical operation with your file? retval = True except ValueError: print('Probably wrong data type?') return retval if __name__ == "__main__": if open_file(file1): open(file1) if open_file(file2) and crunch_file(file2): print('opened and crunched')