Say I have a
class Rocket(object):
def __init__(self):
self.ready = False
def prepare_for_takeoff(self):
self.ready = True
def takeoff(self):
if not self.ready:
raise NotReadyException("not ready!")
print("Liftoff!")
Now, which of the standard exceptions would be most appropriate to derive NotReadyException from? Would it be ValueError, since self has the wrong state/value?
Now, which of the standard exceptions would be most appropriate to derive NotReadyException from?
Exception
Don't mess with anything else.
http://code.google.com/p/soc/wiki/PythonStyleGuide#Exceptions
What are your use cases for exception handling?
If you derived your exception from, say ValueError, would you ever write a handler that used except ValueError: to catch both exceptions and handle them in exactly the same way? Unlikely.
ValueError is a catch-all when more specific exceptions aren't appropriate. Your exception is very specific.
When you have an application-specific exception like this, the odds of it sharing any useful semantics with a built-in exception are low. The odds of actually combining the new one and an existing exception into a single handler are very, very low.
About the only time you'll ever combine an application-specific exception with generic exceptions is to use except Exception: in some catch-all logger.
I'd just derive it from Exception. Programmers who catch ValueError might be quite surprised that they catch your NotReadyException as well.
If you will be defining a lot of similar types of state-related exceptions, and it would be convenient to be able to catch 'em all, you might define a StateError exception and then derive NotReadyException from that.
Related
I'm reading the Python Tutorial.
I came across a part that says:
'''
If you need to determine whether an exception was raised but don’t intend to handle it, a simpler form of the raise statement allows you to re-raise the exception:
'''
try:
raise NameError('HiThere')
except NameError:
print('An exception flew by!')
raise
I don't understand why would one raise an exception, handle it and then re-raise it??
If the programmer doesn't want to handle the exception they shouldn't use a try..except statement in the first place??
It helps if you don't think of exceptions as "mistakes" that have to be caught/corrected, and instead think of them as a way of communicating information.
Sometimes when you catch an exception it's expected, or you can find a way around it. Other times, the exception means you can't do the thing you were trying to do, and so you want to raise an exception to your own caller to let them know why it's not going to work out.
When you're in that situation, sometimes you'll catch the lower-level exception that thwarted your plans, and then raise your own exception (maybe with a more specific type) to communicate your own failure to the caller. Sometimes it might work just as well to simply raise the same exception back to the caller. In the situation where you just want the lower level exception to go all the way up to the caller, you might opt to just not catch it, but what if you want to log a message or clean up some piece of internal state before you go down in flames? That's where the except/raise pattern is useful.
begin_complicated_process()
try:
do_risky_thing()
except ShenanigansError:
log("Did someone say shenanigans?!")
unwind_complicated_process()
raise
complete_complicated_process()
I fully get the general principle of not catching all exception, as explained in this question, for instance (Why is "except: pass" a bad programming practice?). Yet I have found myself writing this sequence to get the source of a file like object:
try:
self.doc.source = source.geturl()
except:
try:
self.doc.source = pathlib.Path(os.path.abspath(source.name)).as_uri()
except:
self.doc.source = None
Clearly with some spelunking I could figure out which specific errors to catch with a reasonable degree of confidence. But at is explained in this question (Python: How can I know which exceptions might be thrown from a method call) you can't ever be quite certain.
So is there a better way to do what I am doing here, which is essentially to say: try this and if it doesn't work try this and if that doesn't work do this. Since this is all about setting a single variable, and there is a fallback of setting it to None, it is not obvious to me wherein the peril lies in this construct.
Maybe it'd be better to put it into a dedicated function ?
def func(source):
try:
return source.geturl()
except Exception:
try:
return pathlib.Path(os.path.abspath(source.name)).as_uri()
except Exception:
pass
Notes on swallowing exceptions
Ignoring any kind of exception is not the best pattern : it'd be better to know what call can raise what kind of exception.
Even if except ...: pass is bad, that's already what you were doing in your example, and here it's clear that we try another way if it fails.
The bad programming practice is basing the error handling on the ability to catch any kind of error. In itself, except: pass is better than except: <lots_of_things_that_wont_raise_again>.
However, the first answer in the post you referred to says something very sensible : pass semantically indicates that you won't do ANYTHING with the exception, and as you do not store in a variable, it also shows that you'll never be able to access it again (well you could, but still..). As /u/Aprillion/, you'll want to at least log these errors, because otherwise, you may be swallowing very useful debugging information, which could make your life (or others) much more difficult at some point.
For example, what happens if there's a bug hidden in geturl, that makes it raises exception in normal cases ? It may stay hidden for long, because this exception will be swallowed and never shown anywhere. Good luck to the debugger to find it !
Ways to improve this
replace except Exception with the exceptions that could be raised
check before an attempt if it is going to fail, so that you don't have to catch an exception
Additionally, you probably want to use a logger to save/show these exceptions somewhere, at least in DEBUG mode.
Clearly with some spelunking I could figure out which specific errors to catch with a reasonable degree of confidence. But at is explained in this question (Python: How can I know which exceptions might be thrown from a method call) you can't ever be quite certain.
Why would that change anything ? If geturl returns specific exception types, you'd only catch these, and you'd want other unexpected errors to bubble up to the interpreter.
The big problem with the givn approach is that if geturl is undefined, or not callable, or take more arguments, this error would not make the interpreter crash, even though it is a clear programming error. That's because except: or except Exception: will catch a lof of Python errors, should it be AttributeError, NameError, ImportError or even SyntaxError.
To conclude, I really think you'd prefer to replace Exception with the list of exceptions you can catch (and at least send the exceptions to a logger). Note that you can write it as such :
try:
return source.geturl()
except (ExceptionA, ExceptionB, ExceptionC):
pass
I have an exception instance and need to execute code depending on it's type. Which way is more clearly - re raise exception or isinstance check?
re raise:
try:
raise exception
except OperationError as err:
result = do_something1(err)
except (InvalidValue, InvalidContext) as err:
result = do_something2(err)
except AnotherException as err:
result = do_something3(err)
except:
pass
isinstance check:
if isinstance(exception, OperationError):
result = do_something1(err)
elif isinstance(exception, (InvalidValue, InvalidContext)):
result = do_something2(err)
elif isinstance(exception, AnotherException):
result = do_something3(err)
PS. Code is used in django process_exception middleware, therefore when re-raising exception I should write except:pass for all unknown exceptions.
First get rid of the except: pass clause - one should never silently pass exceptions, specially in a bare except clause (one should never use a bare except clause anyway).
This being said, the "best" way really depends on concrete use case. In your above example you clearly have different handlers for different exceptions / exceptions sets, so the obvious solution is the first one. Sometimes you do have some code that's common to all or most of the handlers and some code that's specific to one exception or exceptions subset, then you may want to use isinstance for the specific part, ie:
try:
something_that_may_fail()
except (SomeException, SomeOtherException, YetAnotherOne) as e:
do_something_anyway(e)
if isinstance(e, YetAnotherOne):
do_something_specific_to(e)
Now as mkrieger commented, having three or more exceptions to handle may be a code or design smell - the part in the try block is possibly doing too many things - but then again sometimes you don't have much choice (call to a builtin or third-part function that can fail in many different ways...).
You could store the exceptions you want to handle as keys in a dictionary with different functions as their values. Then you can catch all errors in just one except and call the dictionary to make sure the relevant function is run.
error_handler = {
OperationError: do_something1,
InvalidValue: do_something2,
InvalidContext: do_something2,
AnotherException: do_something3,
}
try:
#raise your exception
except (OperationError, InvalidValue, InvalidContext, AnotherException) as err:
result = error_handler[type(err)]()
I suspect there might be a way to programmatically pass error_handler.keys() to except, but the means I've tried in Python2.7 have not worked so far.
Note that as martineau points out, because this uses type(err) as a dictionary key it won't handle derived exception classes the way that isinstance(err, ...) and except (err) would. You'd need to match exact exceptions.
Suppose that I am using a library X that specifies for example that exception.BaseError is the base class for all exceptions of X.
Now, there is another exception, say X.FooError, which of course inherits from exception.BaseError but is more generalized, let's say that it handles invalid input. Let's suppose there are many other such classes, inherting from BaseError but all for generalized cases.
X
|
BaseError
|
FooError
So I want to then check for invalid input. So which exception should I catch? Of course, catching each individual exception is not possible, so I catch the X.BaseError and then print an error message. Or I can catch the X.FooError specifically but then I miss out all the other error cases.
Is this the standard way of doing it -- catch the base exception? If yes, then why do the other exceptions exist? For the generalized case when we want to catch a specific exception?
Catch only the exceptions you can handle. If you can handle both the base exception and the derived exception then catch both. But make sure to put the derived exception first, since the first exception handler found that matches is the one used.
try:
X.foo()
except X.FooError:
pass
except X.BaseError:
pass
As usual, there is good advice in PEP-8, Style Guide for Python Code:
When catching exceptions, mention specific exceptions whenever possible instead of using a bare except: clause.
There's lots more in there, but it's pointless me reproducing it here.
In this case, I would catch the specifics, were I to handle them differently to a BaseError and the BaseError for those that require more general handling. I would stop well short of catching the built-in Exception, however.
You catch a specfic exception by defining it in the except clause, thus:
try:
#do stuff
except X.FooError:
# handle the error
except (X.AnotherError, x.YetAnotherError), exc:
print 'I'm handling %s' % exc
Notice you can handle multiple exception classes by listing them in a tuple.
This question already has answers here:
Closed 12 years ago.
Possible Duplicate:
Does a exception with just a raise have any use?
Is there any value to re-raising an exception with no other code in between?
try:
#code
except Exception:
raise
I was recently looking through some code and saw a few blocks like these with nothing extra in the except block but another raise. I assume this was a mistake and poor decision making, am I right?
I've seen similar code before in a (set of) horrible VB.NET projects. Either the intent was to catch and log exceptions, without ever coming back to finish the logging, or they heard "you must catch exceptions", implemented this functionality, and someone else decided it should just re-raise.
There is no benefit to the above code.
I am not able to come up with something useful, other than to keep it as a placeholder for later insertion to catch useful exceptions.
It kind of avoids re-indenting the code, when you want to include the "try .. except.." blocks later on.
Example built on this question. If there's some other except's in the try block, it can be used to filter the exceptions, but alone it's pointless.
class FruitException(Exception): pass
try:
raise FruitException
except FruitException:
print "we got a bad fruit"
raise
except Exception:
print "not fruit related, irrelevant."
Yes, this is usually a bad practice. The only (somewhat) correct usage I've seen of this pattern was before VB.NET had a Using construct available. Usage looked something like:
Dim myResource As DisposableService
Try
myResource = New DisposableService()
' This might throw an exception....
myResource.DoSomething()
Catch
Throw
Finally
' Perform cleanup on resource
If Not myResource Is Nothing Then
myResource.Dispose()
End If
End Try
Other than that, I really can't think of a good use case for this sort of thing.
sometimes it useful let me give you a real example that i did i my work :
this was is in a decorator that wrap func : so basically what i have wanted is to re-raise the error that i catched when i called the function func so that the decorator don't change the behavior of the function func, because when func raise an exception the exception are send to the GUI so that an error message can pop up to the user,
and for the try except i use it because i want to execute the code in finally even if an exception is raised
try:
result = func(self, *args, **kws)
return result
except Exception, ex:
# If an exception is raised save it also.
logging_data['message'] = str(ex)
logging_data['type'] = 'exception'
# Raise the error catched here so that we could have
# the same behavior as the decorated method.
raise
finally:
# Save logging data in the database
....
hope this will help to understand the use of re-raise
Typically in a try-catch model, any uncaught exception will automatically be thrown (raised?). Catching the exception only to re-throw it may be in the spirit Allman style coding, but serves no functional purpose.
Uh, Imagine
def something(a,b):
try:
// do stuff
except SomethingSpecificToThisFunction:
//handle
except: //Everything else, should likely be handled somewhere else
raise
try:
something("a","b")
except e:
Log(e)
Then again its default behaviour anyways, so might just want to leave it out
There are some approaches with such technics in multithread enviroment. For example to throw something to upper stack level.