Differencebetween 'Raise "Foo"' and 'Raise Exception.New("Foo")'

What is the difference between `raise foo` and `raise Exception.new(foo)`?

Technically, the first raises a RuntimeError with the message set to "foo", and the second raises an Exception with the message set to "foo".

Practically, there is a significant difference between when you would want to use the former and when you want to use the latter.

Simply put, you probably want a RuntimeError not an Exception. A rescue block without an argument will catch RuntimeErrors, but will NOT catch Exceptions. So if you raise an Exception in your code, this code will not catch it:

begin
rescue
end

In order to catch the Exception you will have to do this:

begin
rescue Exception
end

This means that in a sense, an Exception is a "worse" error than a RuntimeError, because you have to do more work to recover from it.

So which you want depends on how your project does its error handling. For instance, in our daemons, the main loop has a blank rescue which will catch RuntimeErrors, report them, and then continue. But in one or two circumstances, we want the daemon to really really die on an error, and in that case we raise an Exception, which goes straight through our "normal error handling code" and out.

And again, if you are writing library code, you probably want a RuntimeError, not an Exception, as users of your library will be surprised if it raises errors that a blank rescue block can't catch, and it will take them a moment to realize why.

Finally, I should say that the RuntimeError is a subclass of the StandardError class, and the actual rule is that although you can raise any type of object, the blank rescue will by default only catch anything that inherits from StandardError. Everything else has to be specific.

What is the difference between Raising Exceptions vs Throwing Exceptions in Ruby?

I think http://hasno.info/ruby-gotchas-and-caveats has a decent explanation of the difference:

catch/throw are not the same as raise/rescue. catch/throw allows you to quickly exit blocks back to a point where a catch is defined for a specific symbol, raise rescue is the real exception handling stuff involving the Exception object.

Difference between raise and raise e?

There is no difference in this case. raise without arguments will always raise the last exception thrown (which is also accessible with sys.exc_info()).

The reason the bytecode is different is because Python is a dynamic language and the interpreter doesn't really "know" that e refers to the (unmodified) exception that is currently being handled. But this may not always be the case, consider:

try:
raise Exception()
except Exception as e:
if foo():
e = OtherException()
raise e

What is e now? There is no way to tell when compiling the bytecode (only when actually running the program).

In simple examples like yours, it might be possible for the Python interpreter to "optimize" the bytecode, but so far no one has done this. And why should they? It's a micro-optimization at best and may still break in subtle ways in obscure conditions. There is a lot of other fruit that is hanging a lot lower than this and is more nutritious to boot ;-)

Manually raising (throwing) an exception in Python

How do I manually throw/raise an exception in Python?

Use the most specific Exception constructor that semantically fits your issue.

Be specific in your message, e.g.:

raise ValueError('A very specific bad thing happened.')

Don't raise generic exceptions

Avoid raising a generic Exception. To catch it, you'll have to catch all other more specific exceptions that subclass it.

Problem 1: Hiding bugs

raise Exception('I know Python!') # Don't! If you catch, likely to hide bugs.

For example:

def demo_bad_catch():
try:
raise ValueError('Represents a hidden bug, do not catch this')
raise Exception('This is the exception you expect to handle')
except Exception as error:
print('Caught this error: ' + repr(error))

>>> demo_bad_catch()
Caught this error: ValueError('Represents a hidden bug, do not catch this',)

Problem 2: Won't catch

And more specific catches won't catch the general exception:

def demo_no_catch():
try:
raise Exception('general exceptions not caught by specific handling')
except ValueError as e:
print('we will not catch exception: Exception')


>>> demo_no_catch()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 3, in demo_no_catch
Exception: general exceptions not caught by specific handling

Best Practices: raise statement

Instead, use the most specific Exception constructor that semantically fits your issue.

raise ValueError('A very specific bad thing happened')

which also handily allows an arbitrary number of arguments to be passed to the constructor:

raise ValueError('A very specific bad thing happened', 'foo', 'bar', 'baz') 

These arguments are accessed by the args attribute on the Exception object. For example:

try:
some_code_that_may_raise_our_value_error()
except ValueError as err:
print(err.args)

prints

('message', 'foo', 'bar', 'baz')    

In Python 2.5, an actual message attribute was added to BaseException in favor of encouraging users to subclass Exceptions and stop using args, but the introduction of message and the original deprecation of args has been retracted.

Best Practices: except clause

When inside an except clause, you might want to, for example, log that a specific type of error happened, and then re-raise. The best way to do this while preserving the stack trace is to use a bare raise statement. For example:

logger = logging.getLogger(__name__)

try:
do_something_in_app_that_breaks_easily()
except AppError as error:
logger.error(error)
raise # just this!
# raise AppError # Don't do this, you'll lose the stack trace!

Don't modify your errors... but if you insist.

You can preserve the stacktrace (and error value) with sys.exc_info(), but this is way more error prone and has compatibility problems between Python 2 and 3, prefer to use a bare raise to re-raise.

To explain - the sys.exc_info() returns the type, value, and traceback.

type, value, traceback = sys.exc_info()

This is the syntax in Python 2 - note this is not compatible with Python 3:

raise AppError, error, sys.exc_info()[2] # avoid this.
# Equivalently, as error *is* the second object:
raise sys.exc_info()[0], sys.exc_info()[1], sys.exc_info()[2]

If you want to, you can modify what happens with your new raise - e.g. setting new args for the instance:

def error():
raise ValueError('oops!')

def catch_error_modify_message():
try:
error()
except ValueError:
error_type, error_instance, traceback = sys.exc_info()
error_instance.args = (error_instance.args[0] + ' <modification>',)
raise error_type, error_instance, traceback

And we have preserved the whole traceback while modifying the args. Note that this is not a best practice and it is invalid syntax in Python 3 (making keeping compatibility much harder to work around).

>>> catch_error_modify_message()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 3, in catch_error_modify_message
File "<stdin>", line 2, in error
ValueError: oops! <modification>

In Python 3:

raise error.with_traceback(sys.exc_info()[2])

Again: avoid manually manipulating tracebacks. It's less efficient and more error prone. And if you're using threading and sys.exc_info you may even get the wrong traceback (especially if you're using exception handling for control flow - which I'd personally tend to avoid.)

Python 3, Exception chaining

In Python 3, you can chain Exceptions, which preserve tracebacks:

raise RuntimeError('specific message') from error

Be aware:

  • this does allow changing the error type raised, and
  • this is not compatible with Python 2.

Deprecated Methods:

These can easily hide and even get into production code. You want to raise an exception, and doing them will raise an exception, but not the one intended!

Valid in Python 2, but not in Python 3 is the following:

raise ValueError, 'message' # Don't do this, it's deprecated!

Only valid in much older versions of Python (2.4 and lower), you may still see people raising strings:

raise 'message' # really really wrong. don't do this.

In all modern versions, this will actually raise a TypeError, because you're not raising a BaseException type. If you're not checking for the right exception and don't have a reviewer that's aware of the issue, it could get into production.

Example Usage

I raise Exceptions to warn consumers of my API if they're using it incorrectly:

def api_func(foo):
'''foo should be either 'baz' or 'bar'. returns something very useful.'''
if foo not in _ALLOWED_ARGS:
raise ValueError('{foo} wrong, use "baz" or "bar"'.format(foo=repr(foo)))

Create your own error types when apropos

"I want to make an error on purpose, so that it would go into the except"

You can create your own error types, if you want to indicate something specific is wrong with your application, just subclass the appropriate point in the exception hierarchy:

class MyAppLookupError(LookupError):
'''raise this when there's a lookup error for my app'''

and usage:

if important_key not in resource_dict and not ok_to_be_missing:
raise MyAppLookupError('resource is missing, and that is not ok.')

In what circumstances, if any, is it appropriate to raise a FileExistsError manually?

As per NobbyNobbs's comment above: if the programmer raises standard exception in his code, it's difficult to work out, during error handling, if a given exception was raised on the application or the system level. Therefore, it's a practice best avoided.

Python raise from usage

The difference is that when you use from, the __cause__ attribute is set and the message states that the exception was directly caused by. If you omit the from then no __cause__ is set, but the __context__ attribute may be set as well, and the traceback then shows the context as during handling something else happened.

Setting the __context__ happens if you used raise in an exception handler; if you used raise anywhere else no __context__ is set either.

If a __cause__ is set, a __suppress_context__ = True flag is also set on the exception; when __suppress_context__ is set to True, the __context__ is ignored when printing a traceback.

When raising from a exception handler where you don't want to show the context (don't want a during handling another exception happened message), then use raise ... from None to set __suppress_context__ to True.

In other words, Python sets a context on exceptions so you can introspect where an exception was raised, letting you see if another exception was replaced by it. You can also add a cause to an exception, making the traceback explicit about the other exception (use different wording), and the context is ignored (but can still be introspected when debugging). Using raise ... from None lets you suppress the context being printed.

See the raise statement documenation:

The from clause is used for exception chaining: if given, the second expression must be another exception class or instance, which will then be attached to the raised exception as the __cause__ attribute (which is writable). If the raised exception is not handled, both exceptions will be printed:

>>> try:
... print(1 / 0)
... except Exception as exc:
... raise RuntimeError("Something bad happened") from exc
...
Traceback (most recent call last):
File "<stdin>", line 2, in <module>
ZeroDivisionError: int division or modulo by zero

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
File "<stdin>", line 4, in <module>
RuntimeError: Something bad happened

A similar mechanism works implicitly if an exception is raised inside an exception handler or a finally clause: the previous exception is then attached as the new exception’s __context__ attribute:

>>> try:
... print(1 / 0)
... except:
... raise RuntimeError("Something bad happened")
...
Traceback (most recent call last):
File "<stdin>", line 2, in <module>
ZeroDivisionError: int division or modulo by zero

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
File "<stdin>", line 4, in <module>
RuntimeError: Something bad happened

Also see the Built-in Exceptions documentation for details on the context and cause information attached to exceptions.

Difference between throw new Exception and new Exception?

new Exception() means create an instance (same as creating new Integer(...))
but no exception will happen until you throw it...

Consider following snippet:

public static void main(String[] args) throws Exception {
foo(1);
foo2(1);
}

private static void foo2(final int number) throws Exception {
Exception ex;
if (number < 0) {
ex = new Exception("No negative number please!");
// throw ex; //nothing happens until you throw it
}

}

private static void foo(final int number) throws Exception {
if (number < 0) {
throw new Exception("No negative number please!");
}

}

the method foo() will THROW an exception if the parameter is negative but
the method foo2() will create an instance of exception if the parameter is negative

How can I write a test which expects an 'Error' to be thrown in Jasmine?

Try using an anonymous function instead:

expect( function(){ parser.parse(raw); } ).toThrow(new Error("Parsing is not possible"));

you should be passing a function into the expect(...) call. Your incorrect code:

// incorrect:
expect(parser.parse(raw)).toThrow(new Error("Parsing is not possible"));

is trying to actually call parser.parse(raw) in an attempt to pass the result into expect(...),



Related Topics



Leave a reply



Submit