This article describes how to handle python errors. This article describes try statements, error stacks, errors recorded, and errors thrown. For more information, see running the program, if an error occurs, you can specify in advance to return an error code so that you can know whether the error is correct and the cause of the error. In calls provided by the operating system, return error codes are very common. For example, if the open () function is used to open a file, the file descriptor (an integer) is returned when the file is successfully opened, and-1 is returned when an error occurs.
It is inconvenient to use the error code to indicate whether an error occurs. because the normal results returned by the function itself are mixed with the error code, the caller must use a large amount of code to determine whether an error occurs:
The code is as follows:
Def foo ():
R = some_function ()
If r = (-1 ):
Return (-1)
# Do something
Return r
Def bar ():
R = foo ()
If r = (-1 ):
Print 'error'
Else:
Pass
Once an error occurs, it must be reported at the first level until a function can handle the error (for example, output an error message to the user ).
Therefore, advanced languages usually have built-in error handling mechanisms such as try... finally.... Python is no exception.
Try
Let's use an example to look at the try mechanism:
The code is as follows:
Try:
Print 'try ...'
R = 10/0.
Print 'result: ', r
Except t ZeroDivisionError, e:
Print 'success T: ', e
Finally:
Print 'Finally ...'
Print 'end'
When we think that some code may have errors, we can use try to run this code. If an error occurs during execution, the subsequent code will not continue to be executed, but will jump directly to the error handling code, that is, explain t statement block. after execution of explain t, if there is a finally statement Block, execute the finally statement block. at this point, the execution is complete.
The above code will produce a division operation error when calculating 10/0:
The code is as follows:
Try...
Partition T: integer pision or modulo by zero
Finally...
END
As can be seen from the output, when an error occurs, the subsequent statement print 'result: 'and r will not be executed, and the progress T is executed because ZeroDivisionError is captured. Finally, the finally statement is executed. Then, the program continues to follow the process.
If the divisor 0 is changed to 2, the execution result is as follows:
The code is as follows:
Try...
Result: 5
Finally...
END
Because no error occurs, the explain t statement block will not be executed, but if finally exists, it will be executed (the finally statement may not exist ).
You can also guess that there should be many types of errors. if there are different types of errors, they should be processed by different blocks of the except t statement. Yes, there can be multiple escape t to capture different types of errors:
The code is as follows:
Try:
Print 'try ...'
R = 10/int ('A ')
Print 'result: ', r
Failed T ValueError, e:
Print 'valueerror: ', e
Except t ZeroDivisionError, e:
Print 'zerodivisionerror: ', e
Finally:
Print 'Finally ...'
Print 'end'
The int () function may throw a ValueError. Therefore, we use a counter t to capture the ValueError and another counter t to capture the ZeroDivisionError.
In addition, if no error occurs, you can add an else next to the limit T statement block. when no error occurs, the else statement is automatically executed:
The code is as follows:
Try:
Print 'try ...'
R = 10/int ('A ')
Print 'result: ', r
Failed T ValueError, e:
Print 'valueerror: ', e
Except t ZeroDivisionError, e:
Print 'zerodivisionerror: ', e
Else:
Print 'no error! '
Finally:
Print 'Finally ...'
Print 'end'
Python errors are actually class. all error types are inherited from BaseException. Therefore, when using the handle T, you must note that it not only captures errors of this type, also, the sub-classes are "exhausted ". For example:
The code is as follows:
Try:
Foo ()
Counter T StandardError, e:
Print 'standardderror'
Failed T ValueError, e:
Print 'valueerror'
ValueError is never captured by the second counter t, because ValueError is a subclass of StandardError. If yes, it is also captured by the first counter t.
All Python errors are derived from the BaseException class. for common error types and inheritance relationships, see here:
Https://docs.python.org/2/library/exceptions.html#exception-hierarchy
Use try... another major advantage of using t to capture errors is that it can be called across multiple layers. for example, the function main () calls foo (), foo () calls bar (), and the result bar () has an error, at this time, as long as main () is captured, it can be processed:
The code is as follows:
Def foo (s ):
Return 10/int (s)
Def bar (s ):
Return foo (s) * 2
Def main ():
Try:
Bar ('0 ')
Counter T StandardError, e:
Print 'error! '
Finally:
Print 'Finally ...'
That is to say, you do not need to capture errors in every possible error. you only need to capture errors at the appropriate level. In this way, the trouble of writing try... faster T... finally is greatly reduced.
Call stack
If the error is not captured, it will be thrown up until it is captured by the Python interpreter, print an error message, and exit the program. Let's take a look at err. py:
The code is as follows:
# Err. py:
Def foo (s ):
Return 10/int (s)
Def bar (s ):
Return foo (s) * 2
Def main ():
Bar ('0 ')
Main ()
The result is as follows:
The code is as follows:
$ Python err. py
Traceback (most recent call last ):
File "err. py", line 11, in
Main ()
File "err. py", line 9, in main
Bar ('0 ')
File "err. py", line 6, in bar
Return foo (s) * 2
File "err. py", line 3, in foo
Return 10/int (s)
ZeroDivisionError: integer pision or modulo by zero
The error is not terrible. The terrible thing is that you don't know where the error is. Interpreting error messages is the key to identifying errors. We can see the entire incorrect call function chain from the top down:
Error message row 1st:
The code is as follows:
Traceback (most recent call last ):
This is the error tracking information.
Row 3:
The code is as follows:
File "err. py", line 11, in
Main ()
An error occurred while calling main (). in the code file err. py, the code is in line 2, but the reason is 11th:
The code is as follows:
File "err. py", line 9, in main
Bar ('0 ')
An error occurred while calling bar ('0'). the error occurs in the code file err. py's 9th lines of code, but the reason is 6th lines:
The code is as follows:
File "err. py", line 6, in bar
Return foo (s) * 2
The reason is that the return foo (s) * 2 statement has an error, but this is not the final reason. continue to the following:
The code is as follows:
File "err. py", line 3, in foo
Return 10/int (s)
The reason is that the return 10/int (s) statement has an error. this is the source of the error because it is printed below:
The code is as follows:
ZeroDivisionError: integer pision or modulo by zero
Based on the error type ZeroDivisionError, we can determine that int (s) itself has no error, but int (s) returns 0. an error occurs when 10/0 is calculated. at this point, locate the error source.
Record error
If you do not capture the error, you can naturally let the Python interpreter print the error stack, but the program is also ended. Now that we can capture errors, we can print out the error stack and analyze the cause of the error. at the same time, let the program continue to run.
The Python built-in logging module can easily record error information:
The code is as follows:
# Err. py
Import logging
Def foo (s ):
Return 10/int (s)
Def bar (s ):
Return foo (s) * 2
Def main ():
Try:
Bar ('0 ')
Counter T StandardError, e:
Logging. exception (e)
Main ()
Print 'end'
It is also an error, but the program continues to run after printing the error message and exits normally:
The code is as follows:
$ Python err. py
ERROR: root: integer pision or modulo by zero
Traceback (most recent call last ):
File "err. py", line 12, in main
Bar ('0 ')
File "err. py", line 8, in bar
Return foo (s) * 2
File "err. py", line 5, in foo
Return 10/int (s)
ZeroDivisionError: integer pision or modulo by zero
END
Through configuration, logging can also record errors to log files for later troubleshooting.
Throw an error
Because the error is a class, capturing an error is to capture an instance of this class. Therefore, errors are not generated out of thin air, but intentionally created and thrown. The built-in functions of Python throw many types of errors, and the functions we compile can also throw errors.
If you want to throw an error, you can first define a wrong class as needed, select the inheritance relationship, and then use the raise statement to throw an error instance:
The code is as follows:
# Err. py
Class FooError (StandardError ):
Pass
Def foo (s ):
N = int (s)
If n = 0:
Raise FooError ('invalid value: % s' % s)
Return 10/n
Run the command to track the custom errors:
The code is as follows:
$ Python err. py
Traceback (most recent call last ):
...
_ Main _. FooError: invalid value: 0
We define our own error types only when necessary. If you can select an existing Python built-in error type (such as ValueError and TypeError), try to use the Python built-in error type.
Finally, let's look at another method of error handling:
The code is as follows:
# Err. py
Def foo (s ):
N = int (s)
Return 10/n
Def bar (s ):
Try:
Return foo (s) * 2
Counter T StandardError, e:
Print 'error! '
Raise
Def main ():
Bar ('0 ')
Main ()
In the bar () function, an Error is clearly captured, but an Error is printed! And then throw the error through the raise Statement. isn't it true?
In fact, this error handling method is not only not ill, but also quite common. The purpose of capturing an error is to record it for later tracking. However, since the current function does not know how to handle the error, the most appropriate way is to continue to throw and let the top-level caller handle the error.
If the raise statement does not contain parameters, the current error is thrown as is. In addition, raise an Error in counter t can also convert one type of Error to another type:
The code is as follows:
Try:
10/0
Except t ZeroDivisionError:
Raise ValueError ('input error! ')
As long as the conversion logic is reasonable, an IOError should never be converted into an unrelated ValueError.
Summary
Python's built-in try... try t... finally is very convenient to handle errors. When an error occurs, it is critical to analyze the error information and locate the code where the error occurs.
The program can also throw an error to allow the caller to handle the error. However, you should clearly write in the document what errors may be thrown and the causes of the errors.