问题
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?
回答1:
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 that is usefull for this:
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 contiune
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 reraise 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 how ever you like. No example since there's one above.
回答2:
assert cond, "text"
is expanded to something like
if cond == False:
raise AssertionError("text")
use assert because it is more readable.
回答3:
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.
回答4:
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.
回答5:
Assertions
- Should only be used for debugging purposes
- Although similar to Raise/Exceptions they serve different purposes, because they are useful to point scenarios where program error cannot be recovered from
- Assertions always raise AssertionError exceptions, here's how they work:
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.- Don’t Use Asserts for Data Validation because of previous point
- A good use case for assertions => make program "explode" if some unexpected state of the program should make it stop under all circumstances => thus, under circumstances where an exception if caught would make program exit altogether.
- If you have a bug-free program, then assertions will/should never be triggered, they serve as health checks for the program
- Careful when using a data structures (such as tuples) as the expression1 in assertions that always evaluate to True for non-empty values => the assertions will always be triggered, breaking down program - eg:
assert (<some_test>, 'warn string')
=> notice the tuple construct (wrong!)
Check: Catching bogus Python asserts on CI by Dan Bader
Raise/Exceptions
- Their purpose is to handle scenarios where program logic is in an exceptional state but you know what logic to recover from that state
- When you raise an exception, you can make the type of the exception appropriate to the error (better control over semantic value) and catch it later => so you can create multiple exception types that you know how to recover from, and handle them
- They are a mechanism for handling known/expected scenarios of run-time errors
- Useful for data validation when using if-statements and raising validation exceptions per scenario
Try
- Is just a syntactic element of coding exceptions handling
BTW, I highly recommend the book, "Python Tricks: The Book" by Dan Bader (from realpython.com)
回答6:
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")
print(dis.dis(foo1))
print(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 None 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 None
回答7:
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]))
回答8:
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.
来源:https://stackoverflow.com/questions/40182944/difference-between-raise-try-and-assert