Should I always specify an exception type in `except` statements?
Asked Answered
U

7

108

When using PyCharm IDE the use of except: without an exception type triggers a reminder from the IDE that this exception clause is Too broad.

Should I be ignoring this advice? Or is it Pythonic to always specific the exception type?

Urson answered 10/2, 2013 at 11:43 Comment(1)
If you want to find out more about this than the answers, google swallowing exceptions. You can all sorts of other interesting dos and don'ts alongside them. Code smells is another one.Panegyric
G
108

It's almost always better to specify an explicit exception type. If you use a naked except: clause, you might end up catching exceptions other than the ones you expect to catch - this can hide bugs or make it harder to debug programs when they aren't doing what you expect.

For example, if you're inserting a row into a database, you might want to catch an exception that indicates that the row already exists, so you can do an update.

try:
    insert(connection, data)
except:
    update(connection, data)

If you specify a bare except:, you would also catch a socket error indicating that the database server has fallen over. It's best to only catch exceptions that you know how to handle - it's often better for the program to fail at the point of the exception than to continue but behave in weird unexpected ways.

One case where you might want to use a bare except: is at the top-level of a program you need to always be running, like a network server. But then, you need to be very careful to log the exceptions, otherwise it'll be impossible to work out what's going wrong. Basically, there should only be at most one place in a program that does this.

A corollary to all of this is that your code should never do raise Exception('some message') because it forces client code to use except: (or except Exception: which is almost as bad). You should define an exception specific to the problem you want to signal (maybe inheriting from some built-in exception subclass like ValueError or TypeError). Or you should raise a specific built-in exception. This enables users of your code to be careful in catching just the exceptions they want to handle.

Googolplex answered 10/2, 2013 at 12:1 Comment(6)
+1 Very true. Even more fun with the example: except: also catches (among many other things) NameError and AttributeError, so if you misspell something in the try block (e.g. your "insert" function is actually called insert_one because someone didn't value consistency as much as they should), it always silently tries to update().Heckelphone
So what about when you need to ensure an exception doesn't get thrown above the current call site? Ie - I've caught all the specific exceptions I can foresee being thrown, now I need to add that "if this thing I haven't thought of gets thrown I need to log it before it kills the running execution context" (such as main())?Personally
That's the kind of situation I'm talking about in the paragraph beginning 'One case...'. It's definitely needed sometimes, but any given program should really only have one place that does that. And you need to be careful that it makes it clear in the log what is happening, otherwise you'll have a frustrating time trying to work out why your program isn't handling the event/request/whatever correctly.Googolplex
@delnan: Worse than that. except Exception: will catch NameError and AttributeError too. What makes bare except: so bad is that it catches stuff that has no business being caught, e.g. SystemExit (raised when you call exit or sys.exit, and now you've prevented an intended exit) and KeyboardInterrupt (again, if the user hit Ctrl-C, you probably don't want to keep running just to spite them). Only the latter makes any real sense to catch, and it should be caught explicitly. At least except Exception: lets those two propagate normally.Tooth
This is the one lint advice that I consistently disagree with. Very often, you want to react the same way no matter what kind of exception that was thrown. I feel like this is a hold-over from some specific advice from early Java that was never let go of.Acnode
I'd add a massive caveat to this... if you are going to re-raise then you should use a bare except if that's what you meant. Switching from except:...raise to except Exception:...raise is really bad because you almost certainly did want to perform that cleanup or logging even if the user hit ctrl-c.Undecagon
A
45

You should not be ignoring the advice that the interpreter gives you.

From the PEP-8 Style Guide for Python :

When catching exceptions, mention specific exceptions whenever possible instead of using a bare except: clause.

For example, use:

 try:
     import platform_specific_module 
 except ImportError:
     platform_specific_module = None 

A bare except: clause will catch SystemExit and KeyboardInterrupt exceptions, making it harder to interrupt a program with Control-C, and can disguise other problems. If you want to catch all exceptions that signal program errors, use except Exception: (bare except is equivalent to except BaseException:).

A good rule of thumb is to limit use of bare 'except' clauses to two cases:

If the exception handler will be printing out or logging the traceback; at least the user will be aware that an error has occurred. If the code needs to do some cleanup work, but then lets the exception propagate upwards with raise. try...finally can be a better way to handle this case.

Afterworld answered 10/2, 2013 at 11:54 Comment(1)
P
9

Not specfic to Python this.

The whole point of exceptions is to deal with the problem as close to where it was caused as possible.

So you keep the code that could in exceptional cirumstances could trigger the problem and the resolution "next" to each other.

The thing is you can't know all the exceptions that could be thrown by a piece of code. All you can know is that if it's a say a file not found exception, then you could trap it and to prompt the user to get one that does or cancel the function.

If you put try catch round that, then no matter what problem there was in your file routine (read only, permissions, UAC, not really a pdf, etc), every one will drop in to your file not found catch, and your user is screaming "but it is there, this code is crap"

Now there are a couple of situation where you might catch everything, but they should be chosen consciously.

They are catch, undo some local action (such as creating or locking a resource, (opening a file on disk to write for instance), then you throw the exception again, to be dealt with at a higher level)

The other you is you don't care why it went wrong. Printing for instance. You might have a catch all round that, to say There is some problem with your printer, please sort it out, and not kill the application because of it. Ona similar vain if your code executed a series of separate tasks using some sort of schedule, you wouldnlt want the entire thing to die, because one of the tasks failed.

Note If you do the above, I can't recommend some sort of exception logging, e.g. try catch log end, highly enough.

Panegyric answered 10/2, 2013 at 12:20 Comment(2)
I would say it's about balance. You have to catch the exception early enough to be able to recover from it and late enough to know where to go with it. That's why Java exception handling causes such havoc, because you have to re-wrap the exception at each step and you loose information.Illfavored
+1 for "you don't care why it went wrong." I'm using it in several places around a single line of code where I parse a date/time from a URL. The third party date/time parsing library doesn't list all of the exceptions it can throw (I've found OverflowError and TypeError in addition to the standard ValueError, but there are probably more), and anyway I really don't care why an exception was thrown, I just want to provide a reasonable error message back to the user saying that something is wrong with the date/time.Nambypamby
B
5

Always specify the exception type, there are many types you don't want to catch, like SyntaxError, KeyboardInterrupt, MemoryError etc.

Braun answered 10/2, 2013 at 11:45 Comment(4)
would using except Exception: avoid the above types that we don't want to catch?Urson
except Exception is fine.Uvula
@HorseloverFat: except Exception catches SyntaxError and MemoryError because it is their base class. KeyboardInterrupt, SystemExit (raised by sys.exit()) are not caught (they are immediate BaseException subclasses)Muriah
sounds like it's not ideal then - better to specify more precisely.Urson
U
4

You will also catch e.g. Control-C with that, so don't do it unless you "throw" it again. However, in that case you should rather use "finally".

Uvula answered 10/2, 2013 at 11:45 Comment(0)
C
4

Here are the places where i use except without type

  1. quick and dirty prototyping

That's the main use in my code for unchecked exceptions

  1. top level main() function, where i log every uncaught exception

I always add this, so that production code does not spill stacktraces

  1. between application layers

I have two ways to do it :

  • First way to do it : when a higher level layer calls a lower level function, it wrap the calls in typed excepts to handle the "top" lower level exceptions. But i add a generic except statement, to detect unhandled lower level exceptions in the lower level functions.

I prefer it this way, i find it easier to detect which exceptions should have been caught appropriately : i "see" the problem better when a lower level exception is logged by a higher level

  • Second way to do it : each top level functions of lower level layers have their code wrapped in a generic except, to it catches all unhandled exception on that specific layer.

Some coworkers prefer this way, as it keeps lower level exceptions in lower level functions, where they "belong".

Centrifugate answered 12/3, 2017 at 8:43 Comment(0)
F
-15

Try this:

try:
    #code
except ValueError:
    pass

I got the answer from this link, if anyone else run into this issue Check it out

Feer answered 26/6, 2017 at 23:53 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.