Python error handling

Source: Internet
Author: User
Tags integer division

In the process of running the program, if an error occurs, you can agree to return an error code beforehand, so that you can know if there is a mistake, and the cause of the error. It is common to return error codes in calls provided by the operating system. For example, a function that opens a file open() , returns a file descriptor (that is, an integer) when it succeeds, and returns when an error occurs -1 .

It is inconvenient to use an error code to indicate whether an error occurred, because the function itself should return the normal result and the error code mixed together, causing the caller to use a lot of code to determine whether the error:

def foo():    r = some_function()    if r==(-1):        return (-1)    # do something    return rdef bar():    r = foo()    if r==(-1):        print ‘Error‘    else:        pass

Once an error occurs, a first-level escalation is needed until a function can handle the error (for example, to output an error message to the user).

So high-level languages usually have a set try...except...finally... of error-handling mechanisms built in, and Python is no exception.

Try

Let's take a look at try the mechanism:

try:    print ‘try...‘    r = 10 / 0    print ‘result:‘, rexcept ZeroDivisionError, e:    print ‘except:‘, efinally:    print ‘finally...‘print ‘END‘

When we think that some code may be wrong, it can be used try to run the code, if the execution error, the subsequent code will not continue to execute, but directly to the error-handling code, that is, the except statement block, except after execution, if there is a finally statement block, then execute the finally statement block, This completes the execution.

The above code 10 / 0 generates a division operation error when it evaluates:

try...except: integer division or modulo by zerofinally...END

As can be seen from the output, when an error occurs, subsequent statements are print ‘result:‘, r not executed, except because they ZeroDivisionError are captured and therefore executed. Finally, the finally statement is executed. The program then continues to follow the process down.

If the divisor 0 is changed 2 , the result of execution is as follows:

try...result: 5finally...END

Because there is no error, the except statement block will not be executed, but finally if there is one, it will be executed (without a finally statement).

You can also guess that there are many kinds of errors, and if different types of errors occur, they should be except handled by different blocks of statements. Yes, there can be multiple except to catch different types of errors:

try:    print ‘try...‘    r = 10 / int(‘a‘)    print ‘result:‘, rexcept ValueError, e:    print ‘ValueError:‘, eexcept ZeroDivisionError, e:    print ‘ZeroDivisionError:‘, efinally:    print ‘finally...‘print ‘END‘

int()The function may be thrown ValueError , so we use one except capture ValueError , with another except capture ZeroDivisionError .

In addition, if no error occurs, you can except add one after the statement block else and automatically execute the statement when no error occurs else :

try:    print ‘try...‘    r = 10 / int(‘a‘)    print ‘result:‘, rexcept ValueError, e:    print ‘ValueError:‘, eexcept ZeroDivisionError, e:    print ‘ZeroDivisionError:‘, eelse:    print ‘no error!‘finally:    print ‘finally...‘print ‘END‘

Python's error is also class, all the error types are inherited from BaseException , so in the use except of note that it not only captures the type of error, but also its subclasses "clean sweep". Like what:

try:    foo()except StandardError, e:    print ‘StandardError‘except ValueError, e:    print ‘ValueError‘

The second one except is never caught ValueError , because ValueError StandardError the subclass, if any, is also captured by the first one except .

All of Python's errors are BaseException derived from the class, common error types and inheritance relationships look here:

Https://docs.python.org/2/library/exceptions.html#exception-hierarchy

try...exceptThere is a huge benefit of using a catch error, which is that you can span multiple layers of calls, such as function main() calls, foo() foo() calls, and bar() result bar() errors, which can be handled as soon as they are main() captured:

def foo(s):    return 10 / int(s)def bar(s):    return foo(s) * 2def main():    try:        bar(‘0‘)    except StandardError, e:        print ‘Error!‘    finally:        print ‘finally...‘

In other words, there is no need to catch errors in every possible error, as long as the error is captured at the appropriate level. In this way, it greatly reduces the try...except...finally trouble of writing.

Call stack

If the error is not captured, it is thrown up and then caught by the Python interpreter, prints an error message, and the program exits. Look at err.py :

# err.py:def foo(s):    return 10 / int(s)def bar(s):    return foo(s) * 2def main():    bar(‘0‘)main()

Execution, the results are as follows:

$ python err.pyTraceback (most recent call last):  File "err.py", line 11, in <module>    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 division or modulo by zero

It's not scary to make a mistake, but it's scary to know where it went wrong. Interpreting error messages is the key to locating errors. We can see the entire wrong call function chain from the top down:

Error message Line 1th:

Traceback (most recent call last):

Tell us that this is the wrong tracking information.

Line 2nd:

  File "err.py", line 11, in <module>    main()

The call main() made an error in the err.py 11th line of code in the code file, but the reason is line 9th:

  File "err.py", line 9, in main    bar(‘0‘)

The call bar(‘0‘) made an error in the err.py 9th line of code in the code file, but the reason is line 6th:

  File "err.py", line 6, in bar    return foo(s) * 2

The reason is that return foo(s) * 2 this statement is wrong, but this is not the final reason, continue to look down:

  File "err.py", line 3, in foo    return 10 / int(s)

The reason is that return 10 / int(s) this statement went wrong, which is the source of the error because it prints:

ZeroDivisionError: integer division or modulo by zero

Depending on the type of error, ZeroDivisionError we judge that int(s) there is no error in itself, but int(s) returns 0 , when the calculation 10 / 0 is wrong, to find the source of the error.

Log errors

If you do not catch an error, it is natural for the Python interpreter to print out the error stack, but the program is ended. Now that we can catch the error, we can print out the error stack, analyze the cause of the error, and let the program go on.

Python's built-in logging modules make it very easy to log error messages:

# err.pyimport loggingdef foo(s):    return 10 / int(s)def bar(s):    return foo(s) * 2def main():    try:        bar(‘0‘)    except StandardError, e:        logging.exception(e)main()print ‘END‘

The same error occurs, but the program continues to execute after printing the error message and exits normally:

$ python err.pyERROR:root:integer division or modulo by zeroTraceback (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 division or modulo by zeroEND

Through the configuration, the logging error can also be recorded in the log file, to facilitate the subsequent troubleshooting.

Throw error

Because the error is class, capturing an error is capturing an instance of the class. As a result, errors are not generated in a vacuum, but are intentionally created and thrown. Python's built-in functions throw many types of errors, and the functions we write ourselves can also throw errors.

If you want to throw an error, you can first define an incorrect class, choose a good inheritance relationship, and then raise throw an instance of the error with the statement, as needed:

# err.pyclass FooError(StandardError):    passdef foo(s):    n = int(s)    if n==0:        raise FooError(‘invalid value: %s‘ % s)    return 10 / n

execution, you can finally trace to our own definition of the error:

$ python err.pyTraceback (most recent call last):  ...__main__.FooError: invalid value: 0

Define our own error types only when necessary. If you can choose a built-in error type that Python already has (such as valueerror,typeerror), use the Python built-in error type as much as possible.

Finally, let's look at another way of handling errors:

# err.pydef foo(s):    n = int(s)    return 10 / ndef bar(s):    try:        return foo(s) * 2    except StandardError, e:        print ‘Error!‘        raisedef main():    bar(‘0‘)main()

In the bar() function, we have obviously caught the error, but, after printing one Error! , and then throw the error through the raise statement, this is not sick?

In fact, this method of error treatment is not only not sick, but also quite common. The purpose of capturing errors is simply to record and facilitate follow-up. However, because the current function does not know what to do with the error, the most appropriate way is to continue to throw up and let the top-level caller handle it.

raiseIf the statement is not with a parameter, the current error is thrown. In addition, except in raise one error, you can convert one type of error to another type:

try:    10 / 0except ZeroDivisionError:    raise ValueError(‘input error!‘)

As long as it is reasonable to convert the logic can be, but, should never be IOError converted into irrelevant ValueError .

Summary

Python built-in try...except...finally to handle errors is very convenient. When an error occurs, it is critical to parse the error message and locate the code location where the error occurred.

The program can also actively throw an error, allowing the caller to handle the corresponding error. However, you should write clearly in your document what errors might be thrown and why the error occurred.

Python error handling

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.