Python3 errors and exceptions


As a Python beginner, when you first learn Python programming, you will often see some error messages. We have not mentioned them before, but we will introduce them specifically in this chapter.

There are two types of errors in Python that are easy to identify: syntax errors and exceptions.

Grammar errors

Python grammatical errors, or parsing errors, are often encountered by beginners, as shown in the following example

>>> while True print('Hello world')
  File "<stdin>", line 1, in ?
    while True print('Hello world')
                   ^
SyntaxError: invalid syntax

In this example, the function print() An error was detected because a colon (:) was missing in front of it.

The parser points out the line in error and marks the first error found with a small arrow.

Exception

Even if the syntax of the Python program is correct, errors may occur when running it. Errors detected during runtime are called exceptions.

Most exceptions will not be handled by the program, and are displayed here in the form of error messages:

>>> 10 * (1/0)
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
ZeroDivisionError: division by zero
>>> 4 + spam*3
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
NameError: name 'spam' is not defined
>>> '2' + 2
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
TypeError: Can't convert 'int' object to str implicitly

Exceptions appear in different types, and these types are printed as part of the information. : The types in the example are ZeroDivisionError, NameError and TypeError.

The front part of the error message shows the context in which the exception occurred, and displays specific information in the form of a call stack.

Exception handling

In the following example, the user is allowed to enter a legal integer, but the user is allowed to interrupt the program (using Control-C or the method provided by the operating system). User-interrupted messages raise a KeyboardInterrupt exception.

>>> while True:
        try:
            x = int(input("Please enter a number: "))
            break
        except ValueError:
            print("Oops!  That was no valid number.  Try again   ")

The try statement works as follows;

  • First, the try clause (the statement between the keyword try and the keyword except) is executed

  • If no exception occurs, the except clause is ignored and the try clause ends after execution.

  • If an exception occurs during the execution of the try clause, the remainder of the try clause will be ignored. If the exception type matches the name after except, the corresponding except clause will be executed. Finally execute the code after the try statement.

  • If an exception does not match any except, then the exception will be passed to the upper try.

A try statement may contain multiple except clauses to handle different specific exceptions. At most one branch will be executed.

The handler will only handle exceptions in the corresponding try clause, not exceptions in other try handlers.

An except clause can handle multiple exceptions at the same time. These exceptions will be placed in parentheses to become a tuple, for example:

    except (RuntimeError, TypeError, NameError):
        pass

The last except clause can ignore the name of the exception. , it will be used as a wildcard. You can use this method to print an error message and then throw the exception again.

import sys

try:
    f = open('myfile.txt')
    s = f.readline()
    i = int(s.strip())
except OSError as err:
    print("OS error: {0}".format(err))
except ValueError:
    print("Could not convert data to an integer.")
except:
    print("Unexpected error:", sys.exc_info()[0])
    raise

try The except statement also has an optional else clause. If this clause is used, it must be placed after all except clauses. This clause will be executed when no exception occurs in the try clause. For example:

for arg in sys.argv[1:]:
    try:
        f = open(arg, 'r')
    except IOError:
        print('cannot open', arg)
    else:
        print(arg, 'has', len(f.readlines()), 'lines')
        f.close()

Using the else clause is better than putting all statements in the try clause, so as to avoid some unexpected exceptions that are not caught by except.

Exception handling not only handles exceptions that occur directly in the try clause, but also handles exceptions thrown in functions called in the clause (even functions called indirectly). For example:

>>> def this_fails():
        x = 1/0
   
>>> try:
        this_fails()
    except ZeroDivisionError as err:
        print('Handling run-time error:', err)
   
Handling run-time error: int division or modulo by zero

Throw an exception

Python uses the raise statement to throw a specified exception. For example:

>>> raise NameError('HiThere')
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
NameError: HiThere

raise The only parameter specifies the exception to be thrown. It must be an exception instance or an exception class (that is, a subclass of Exception).

If you just want to know if this threw an exception and don't want to handle it, then a simple raise statement can throw it again.

>>> try:
        raise NameError('HiThere')
    except NameError:
        print('An exception flew by!')
        raise
   
An exception flew by!
Traceback (most recent call last):
  File "<stdin>", line 2, in ?
NameError: HiThere

User-defined exceptions

You can have your own exceptions by creating a new exception class. Exceptions should inherit from the Exception class, either directly or indirectly, for example:

>>> class MyError(Exception):
        def __init__(self, value):
            self.value = value
        def __str__(self):
            return repr(self.value)
   
>>> try:
        raise MyError(2*2)
    except MyError as e:
        print('My exception occurred, value:', e.value)
   
My exception occurred, value: 4
>>> raise MyError('oops!')
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
__main__.MyError: 'oops!'

In this example, the default __init__() of class Exception is overridden.

<pException classes can do anything like other classes, but they are usually simpler, providing only some error-related properties and allowing the code that handles the exception to easily obtain this information. < p="">

When creating a module that may throw multiple different exceptions, a common approach is to create a base exception class for the package, and then provide different errors based on this base class. Create different subclasses:

class Error(Exception):
    """Base class for exceptions in this module."""
    pass

class InputError(Error):
    """Exception raised for errors in the input.

    Attributes:
        expression -- input expression in which the error occurred
        message -- explanation of the error
    """

    def __init__(self, expression, message):
        self.expression = expression
        self.message = message

class TransitionError(Error):
    """Raised when an operation attempts a state transition that's not
    allowed.

    Attributes:
        previous -- state at beginning of transition
        next -- attempted new state
        message -- explanation of why the specific transition is not allowed
    """

    def __init__(self, previous, next, message):
        self.previous = previous
        self.next = next
        self.message = message

Most exception names end with "Error", just like standard exception naming.


Define cleanup behavior

The try statement has another optional clause, which defines the cleanup behavior that will be executed under any circumstances. For example:

>>> try:
        raise KeyboardInterrupt
	finally:
        print('Goodbye, world!')
   
Goodbye, world!
KeyboardInterrupt

In the above example, the finally clause will be executed regardless of whether an exception occurs in the try clause.

If an exception is thrown in the try clause (or in the except and else clauses) and there is no except to intercept it, then the exception will occur again after the finally clause is executed. was thrown.

The following is a more complex example (containing except and finally clauses in the same try statement):

>>> def divide(x, y):
        try:
            result = x / y
        except ZeroDivisionError:
            print("division by zero!")
        else:
            print("result is", result)
        finally:
            print("executing finally clause")
   
>>> divide(2, 1)
result is 2.0
executing finally clause
>>> divide(2, 0)
division by zero!
executing finally clause
>>> divide("2", "1")
executing finally clause
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
  File "<stdin>", line 3, in divide
TypeError: unsupported operand type(s) for /: 'str' and 'str'

Predefined cleanup behavior

Some The object defines standard cleanup behavior. Regardless of whether the system successfully uses it, once it is no longer needed, this standard cleanup behavior will be executed.

This example shows trying to open a file and then print the contents to the screen:

for line in open("myfile.txt"):
    print(line, end="")

The problem with the above code is that when execution is completed, the file will remain open. , and has not been closed.

The keyword with statement can ensure that objects such as files will correctly execute their cleaning methods after use:

with open("myfile.txt") as f:
    for line in f:
        print(line, end="")

After the above code is executed, even if Something went wrong during processing and file f was always closed.