Reputation: 1191
I have been learning Python for a while and the raise
function and assert
are (what I realised is that both of them crash the app, unlike try - except) really similar and I can't see a situation where you would use raise
or assert
over try
.
So, what is the difference between raise
, try
, and assert
?
Upvotes: 107
Views: 123062
Reputation: 1636
The statement assert
can be used for checking conditions at runtime, but is removed if optimizations are requested from Python. The extended form is:
assert condition, message
and is equivalent to:
if __debug__:
if not condition:
raise AssertionError(message)
where __debug__
is True
if Python was not started with the option -O
.
So the statement assert condition, message
is similar to:
if not condition:
raise AssertionError(message)
in that both raise an AssertionError
. The difference is that assert condition, message
can be removed from the executed bytecode by optimizations (when those are enabled--by default they are not applied in CPython). In contrast, raise AssertionError(message)
will in all cases be executed.
Thus, if the code should under all circumstances check and raise an AssertionError
if the check fails, then writing if not condition: raise AssertionError
is necessary.
Upvotes: 138
Reputation: 24018
When they are in place, there is no difference between assert
and raise AssertionError
, they will compile to the exact same bytecode:
import dis
def foo1(param):
assert param, "fail"
def foo2(param):
if not param:
raise AssertionError("fail")
dis.dis(foo1)
print("*" * 60)
dis.dis(foo2)
Output:
4 0 LOAD_FAST 0 (param) 2 POP_JUMP_IF_TRUE 12 4 LOAD_GLOBAL 0 (AssertionError) 6 LOAD_CONST 1 ('fail') 8 CALL_FUNCTION 1 10 RAISE_VARARGS 1 >> 12 LOAD_CONST 0 (None) 14 RETURN_VALUE ************************************************************ 7 0 LOAD_FAST 0 (param) 2 POP_JUMP_IF_TRUE 12 8 4 LOAD_GLOBAL 0 (AssertionError) 6 LOAD_CONST 1 ('fail') 8 CALL_FUNCTION 1 10 RAISE_VARARGS 1 >> 12 LOAD_CONST 0 (None) 14 RETURN_VALUE
But keep i mind that assert
stataments will be disabled when running Python with the -O
or -OO
flags, this is not the case with any raise statements.
Upvotes: 10
Reputation: 4991
Assert:
Used when you want to "stop" the script based on a certain condition and return something to help debug faster:
list_ = ["a","b","x"]
assert "x" in list_, "x is not in the list"
print("passed")
#>> prints passed
list_ = ["a","b","c"]
assert "x" in list_, "x is not in the list"
print("passed")
#>>
Traceback (most recent call last):
File "python", line 2, in <module>
AssertionError: x is not in the list
Raise:
Two reasons where this is useful:
1/ To be used with try and except blocks. Raise an error of your choosing, could be custom like below and doesn't stop the script if you pass
or continue
the script; or can be predefined errors raise ValueError()
class Custom_error(BaseException):
pass
try:
print("hello")
raise Custom_error
print("world")
except Custom_error:
print("found it not stopping now")
print("im outside")
>> hello
>> found it not stopping now
>> im outside
Noticed it didn't stop? We can stop it using just exit(1) in the except block.
2/ Raise can also be used to re-raise the current error to pass it up the stack to see if something else can handle it.
except SomeError, e:
if not can_handle(e):
raise
someone_take_care_of_it(e)
Try/Except blocks:
Does exactly what you think, tries something if an error comes up you catch it and deal with it however you like. No example since there's one above.
Upvotes: 74
Reputation: 2598
The other answers explain the differences pretty well, but many fail to mention that assert
statements are ignored when the -O optimizer flag is used.
One option to get similarly concise syntax to assert
, still have the exceptions take effect when -O is in use, and get the benefits of being able to raise specific exception types is to define a utility function like this:
def raiseif(cond, msg="", exc=AssertionError):
if cond:
raise exc(msg)
raiseif(x != y, "x should equal y")
The logic is inverted from assert
but you can easily change that if you want.
Upvotes: 1
Reputation: 3476
Assertions
syntax: assert_stmt ::= "assert" expression1 ["," expression2]
at execution time it translates to:
if __debug__:
if not expression1:
raise AssertionError(expression2)
__debug__
is a built-in flag that is usually true, but if optimisations are triggered it will be false, thus assertions will be dead code => disabled with the -O and -OO flags when starting Python (or PYTHONOPTIMIZE env variable in CPython), so, don't rely on them for code logic.assert (<some_test>, 'warn string')
=> notice the tuple construct (wrong!)Check: Catching bogus Python asserts on CI by Dan Bader
Raise/Exceptions
Try
BTW, I highly recommend the book, "Python Tricks: The Book" by Dan Bader (from realpython.com)
Upvotes: 29
Reputation: 2358
Assert is generally used by testing code to make sure that something worked:
def test_bool():
assert True != False
Where as try, raise and except makeup exception handling which is the preferred way in python to handle and propagate errors.
Most libraries and the python built-ins will raise and Exception of one type or another if something goes wrong. Often in you own code you will also want to raise an exception when you detect something going wrong. Let's say as an example you were writing an email address validator and you wanted to raise an exception if the address didn't contain an @ sign. you could have something like (This is toy code, don't actually validate emails like this):
def validate_email(address):
if not "@" in address:
raise ValueError("Email Addresses must contain @ sign")
Then somewhere else in your code you can call the validate_email function and if it fails an exception will be thrown.
try:
validate_email("Mynameisjoe.com")
except ValueError as ex:
print("We can do some special invalid input handling here, Like ask the user to retry the input")
finally:
close_my_connection()
print("Finally always runs whether we succeed or not. Good for clean up like shutting things down.")
The important thing to know is that when an exception is raised it gets passed up the call stack until it finds a handler. If it never finds a handler then it will crash the program with the exception and the stack trace.
One thing you don't want to do is something like:
if __name__ == '__main__':
try:
print(1/0)
except Exception as ex:
pass
Now you have no way of knowing why your application blew up.
One thing you will see often which is ok is something like:
import logging
if __name__ == '__main__':
try:
print(1/0)
except Exception as ex:
logging.exception(ex)
raise
The raise in this case since it has no parameters re-raises the same error. Often in web code you will see something similar that does not re-raise the exception because it will send the 500 error to the client and then carry on with the next request, so in that case you don't want the program to end.
Upvotes: 1
Reputation: 77337
try/except
blocks let you catch and manage exceptions. Exceptions can be triggered by raise
, assert
, and a large number of errors such as trying to index an empty list. raise
is typically used when you have detected an error condition. assert
is similar but the exception is only raised if a condition is met.
raise
and assert
have a different philosophy. There are many "normal" errors in code that you detect and raise errors on. Perhaps a web site doesn't exist or a parameter value is out of range.
Assertions are generally reserved for "I swear this cannot happen" issues that seem to happen anyway. Its more like runtime debugging than normal runtime error detection. Assertions can be disabled if you use the -O
flag or run from .pyo
files instead of .pyc
files, so they should not be part of regular error detection.
If production quality code raises an exception, then figure out what you did wrong. If it raises an AssertionError
, you've got a bigger problem.
Upvotes: 23
Reputation: 60944
Exceptions are what Python (and some other languages) use to deal with errors that arise when executing code. raise ExceptionName
is saying that there is an error in the code, and specifies what kind of problem it is by raising the Exception associated with that problem. assert expression
evaluate expression
and raises an Exception if it is false.
try
is used to execute code that might raise an Exception that you're expecting. Instead of stopping the program, you can "catch" the exception and deal with it in your code.
Example: Let's say that you have a dictionary and a list. You want to look things from the list in the dictionary until you reach one that isn't in the dictionary:
try:
for item in my_list:
print(my_dictionary[item])
except KeyError as e: #KeyError is the Exception raised when a key is not in a dictionary
print('There is no {} in the dictionary'.format(e.args[0]))
Upvotes: 1
Reputation: 33275
raise
- raise an exception.
assert
- raise an exception if a given condition is (or isn't) true.
try
- execute some code that might raise an exception, and if so, catch it.
Upvotes: 37