The rest of this chapter will specifically introduce Python's built-in exception mechanism. The entire Python exception mechanism is built in accordance with object-oriented specifications, which makes it flexible and extensible. Even if everyone is not familiar with object-oriented programming (OOP), there is no need to learn object-oriented technology when using exceptions.
Exceptions are raise
objects automatically generated by Python functions . After the exception object is generated, the raise
statement that caused the exception will change the execution mode of the Python program, which is different from the normal execution flow. Instead of continuing to execute raise
the next statement, or executing the next statement after the exception is generated, it retrieves the current function call chain and finds a handler that can handle the current exception. If an exception handler is found, it will be called and the exception object will be accessed for more information. If no suitable exception handler is found, the program will abort and report an error.
{Easy to request and hard to recognize!}
In general, Python's approach to error handling is different from common approaches in languages such as Java. Those languages rely on checking out as much as possible before the error occurs, because handling the exception after the error occurs often requires a variety of high costs. This approach has been introduced in the first section of this chapter, and is sometimes called the "Look Before You Leap" (LBYL) approach.
However, Python may rely more on "exceptions" and deal with errors after they occur. Although this dependency may seem risky, if the "exception" can be used properly, the code will be lighter and more readable, and will only be processed when an error occurs. This Python-style error handling method is often called "Easier to Ask Forgiveness than Permission" (EAFP).
14.2.1 Types of Python Exceptions
In order to correctly reflect the actual cause of the error, or the abnormal situation that needs to be reported, various types of abnormal objects can be generated. There are many types of exception objects provided by Python 3.6:
BaseException
SystemExit
KeyboardInterrupt
GeneratorExit
Exception
StopIteration
ArithmeticError
FloatingPointError
OverflowError
ZeroDivisionError
AssertionError
AttributeError
BufferError
EOFError
ImportError
ModuleNotFoundError
LookupError
IndexError
KeyError
MemoryError
NameError
UnboundLocalError
OSError
BlockingIOError
ChildProcessError
ConnectionError
BrokenPipeError
ConnectionAbortedError
ConnectionRefusedError
ConnectionResetError
FileExistsError
FileNotFoundError
InterruptedError
IsADirectoryError
NotADirectoryError
PermissionError
ProcessLookupError
TimeoutError
ReferenceError
RuntimeError
NotImplementedError
RecursionError
SyntaxError
IndentationError
TabError
SystemError
TypeError
ValueError
UnicodeError
UnicodeDecodeError
UnicodeEncodeError
UnicodeTranslateError
Warning
DeprecationWarning
PendingDeprecationWarning
RuntimeWarning
SyntaxWarning
UserWarning
FutureWarning
ImportWarning
UnicodeWarning
BytesWarningException
ResourceWarning
Python's exception objects are constructed hierarchically, and the indentation in the above exception list illustrates this point. As shown in Chapter 10 __builtins__
, an alphabetical list of exception objects can be obtained from the module.
Each exception is a Python class, inherited from the parent exception class. But if you have not been exposed to OOP, don't worry. For example, IndexError
also LookupError
classes and Exception
classes (through inheritance), and still BaseException
.
This hierarchical structure is intentional, most exceptions are inherited from Exception
, it is strongly recommended that all user-defined exceptions should also be Exception
subclasses, not BaseException
subclasses. The reason is as follows.
try:
# 执行一些异常操作
except Exception:
# 处理异常
{:—} In the above code, you can still use Ctrl+C to suspend try
the execution of the statement block without causing exception handling code. Because the KeyboardInterrupt
exception is not Exception
a subclass.
Although the explanation of each exception can be found in the documentation, the most common exceptions can be quickly familiarized with hands-on programming.
14.2.2 Throw an exception
Exceptions can be raised by many Python built-in functions:
>>> alist = [1, 2, 3]
>>> element = alist[7]
Traceback (innermost last):
File "<stdin>", line 1, in ?
IndexError: list index out of range
Python's built-in error checking code will detect that the index value of the list requested to be read in the second line does not exist and raise IndexError
an exception. The exception is always passed back to the top layer, which is the interactive Python interpreter, and the interpreter handles it by printing a message indicating that an exception has occurred.
In your own code, you can also use raise
statements to explicitly raise exceptions. raise
The most basic form of the statement is as follows:
raise exception(args)
exception(args)
Part of it will create an exception object. The parameters of the new exception object should usually be values that help determine the error condition, as will be introduced later. After the exception object is created, it raise
will be thrown up the Python function stack, which is raise
the function currently executed to the statement. The newly created exception will be thrown to the closest type of exception catching code block on the stack. If the corresponding exception catching code block is not found until the top level of the program, the program will stop running and report an error. In the interactive session, the error message will be printed to the console.
Please try the following code:
>>> raise IndexError("Just kidding")
Traceback (innermost last):
File "<stdin>", line 1, in ?
IndexError: Just kidding
raise
The messages generated above seem to be similar to all previous Python list index error messages at first glance. A closer look will reveal that this is not the case. The actual error is not as serious as the previous error.
String parameters are often used when creating exceptions. If the first parameter is given, most of the built-in Python exceptions will think that the parameter is the information to be displayed as an explanation of the event that has occurred. However, this is not always the case, because each exception type has its own class, and the parameters required to create an exception of that class are completely determined by the definition of the class. In addition, custom exceptions created by programmers are often used for purposes other than error handling, so text messages may not be used as parameters.
14.2.3 Catch and handle exceptions
The point of the exception mechanism is not to stop the program with an error message. It is never difficult to implement the abort function in the program. The special feature of the exception mechanism is that it does not necessarily stop the program from running. By defining appropriate exception handling code, you can ensure that common exceptions will not cause the program to fail. It may be possible to display an error message or other methods to the user, or it may be possible to solve the problem without causing the program to crash.
The following illustrates the basic syntax of Python exception is caught and handled, uses try
, and except
sometimes by else
keyword:
try:
body
except exception_type1 as var1:
exception_code1
except exception_type2 as var2:
exception_code2
.
.
.
except:
default_exception_code
else:
else_body
finally:
finally_body
The first part of the try
statement is executed body
. If the execution is successful, that is, the try
statement did not catch an exception thrown, then execute the else_body
part, and the try
statement is executed. Because there is a finally
statement here , part of it will be executed next finally_body
. If an exception is try
thrown, each except
clause will be searched in turn to find the clause that matches the associated exception type with the thrown exception. If a matching except
clause is found , the thrown exception is assigned to the variable, the variable name is given after the associated exception type, and except
the exception handling code in the matching clause is executed . For example, if except exception_type as var:
this line matches a thrown exception exc
, a variable will be created var
, and the value except
will be var
assigned to before executing the exception handling code of the statement exc
. var
It is not necessary, it can only appear except exception_type
: this way of writing, a given type of exception can still be caught, but the exception will not be assigned to a variable.
If no matching except
clause is found , the try
statement cannot handle the thrown exception, and the exception will continue to be thrown to the upper layer of the function call chain, expecting the outer layer try
to handle it.
try
The last except
clause in the statement can not specify any exception types at all, so that all types of exceptions will be handled. For some debugging tasks and very fast prototyping, this technique may be convenient. But usually this is not a good practice, all errors are except
covered up by clauses, which may make some behaviors of the program difficult to understand.
try
The else
clauses of the statement are optional and are rarely used. The clause will be executed if and only if no error is thrown when part of the try
statement is executed.body
else
try
Statement finally
clause is also optional, in try
, except
, else
parts are executed after the implementation. If try
an exception is raised in the block and has not been except
processed by any block, finally
the exception will be raised again after the block is executed. Because the finally
block will always be executed, it can provide an opportunity to add resource cleanup code through operations such as closing the file and resetting variables after the exception handling is completed.
Hands-on: Catch the exception and write code to read the two numbers entered by the user and divide the first number by the second number. Check and catch the exception when the second number is 0 (
ZeroDivisionError
).
14.2.4 Customize new exception
Defining your own exception is very simple. It can be done with the following two lines of code:
class MyError(Exception):
pass
{:—} The above code creates a class that will inherit Exception
all the content in the base class . But if you don’t want to clarify the details, you can ignore it.
The above exceptions can be raised, caught, and handled like any other exception. If a parameter is given and it is not captured and processed, the parameter value will be printed at the end of the trace information:
>>> raise MyError("Some information about what went wrong")
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
__main__.MyError: Some information about what went wrong
Of course, the above parameters are also accessible in the exception handling code written by yourself:
try:
raise MyError("Some information about what went wrong")
except MyError as error:
print("Situation:", error)
The result of the operation will be as follows:
Situation: Some information about what went wrong
If an exception is thrown with multiple parameters, these parameters will be passed into the exception handling code in the form of a tuple, and the tuple can be accessed through error
the args
attributes of the variable :
try:
raise MyError("Some information", "my_filename", 3)
except MyError as error:
print("Situation: {0} with file {1}\n error code: {2}".format(
error.args[0],
error.args[1], error.args[2]))
The result of the operation will be as follows:
Situation: Some information with file my_filename
error code: 3
The exception type is a regular Python class and inherits from the Exception
class, so it is a relatively simple matter to establish your own exception type hierarchy for your own code. When reading this book for the first time, you don't need to care about this process. After reading Chapter 15, you can check back anytime. How to create your own exception is completely determined by requirements. If you are writing a small program that may only generate some unique errors or exceptions, then use the Exception
subclass of the class as described above . If you are writing a large, multi-file, specific function code library (such as weather forecast library), you can consider defining a separate WeatherLibraryException
class named , and then define all the different exceptions in the library as WeatherLibraryException
subclasses.
Velocity measurement Topic: "Exception" class assumptions
MyError
inherited fromException
class, I askexcept Exception as e
, andexcept MyError as e
what is the difference?
14.2.5 Using assert statements to debug programs
assert
Statement is raise
a special form of statement:
assert expression, argument
If expression
the settlement result is False
and the system variable __debug__
is also True
, argument
an AssertionError
exception with optional parameters will be raised . __debug__
The variable defaults to True
. Start the Python interpreter with -O
or -OO
parameter, or set the system variable PYTHONOPTIMIZE
to True
, you can __debug__
set to False
. Optional parameters argument
can be used to place assert
the explanation information.
If __debug__
is False
, then the code generator will not assert
create the code statement. In the development phase, you can use assert
statements to cooperate with debugging statements to test the code. assert
The statement can be stored in the code for future use, and there is no running overhead during normal use:
>>> x = (1, 2, 3)
>>> assert len(x) > 5, "len(x) not > 5"
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AssertionError: len(x) not > 5
Hands-on question: assert statement Please write a simple program that allows the user to enter a number, and use the
assert
statement to cause an exception when the number is 0. First, please test to ensureassert
the execution of the statement, and then disable it through the methods mentioned in this sectionassert
.
14.2.6 Abnormal inheritance structure
As mentioned before, the exception of Python is a layered architecture. This section will give an in-depth introduction to this architecture, including except
the meaning of this architecture for how clauses catch exceptions.
Consider the following code:
try:
body
except LookupError as error:
exception code
except IndexError as error:
exception code
Here will be captured IndexError
and LookupError
the two exceptions. It happens to IndexError
be LookupError
a subclass. If it is body
thrown IndexError
, then the error will be first except LookupError as error:
detected by the " " line. Because of IndexError
inheritance LookupError
, the first except
clause will be successfully executed, and the second except
clause will never be used because its operating conditions are except
included in the first clause.
On the contrary, except
it may make sense to reverse the order of the two clauses. Thus the process in the first clause IndexError
, the second clause processing other IndexError
than LookupError
.
14.2.7 Example: Disk writing program written in Python
This section will return to the example of the word processing program. When writing a document to the disk, the program needs to check for insufficient disk space:
def save_to_file(filename) :
try:
save_text_to_file(filename)
save_formats_to_file(filename)
save_prefs_to_file(filename)
.
.
.
except IOError:
...处理错误...
def save_text_to_file(filename):
...调用底层函数来写入文本大小...
...调用底层函数来写入实际的文本数据...
.
.
.
Note that the error handling code is very inconspicuous, save_to_file
and is put together with a series of disk write calls in the function. None of those disk write sub-functions need to contain any error handling code. The program will be easier to develop at the beginning, and it is also very simple to add error handling code later. Programmers often do this, although this order of implementation is not optimal.
It is also worth noting that the above code will not only respond to the disk full error, but will respond to all IOError
exceptions. Python's built-in function will automatically raise IOError
an exception whenever it cannot complete an I/O request, regardless of the reason . This may be enough to meet the needs, but if you want to individually identify the disk is full, you have to do some more operations. You can except
check how much free space the disk has in the statement body. If the disk space is insufficient, it is obvious that a disk full problem has occurred and should except
be dealt with in the statement body. If it is not a disk space issue, then except
the code in the statement body can throw this IOError
to the upper layer of the call chain so that it can be handled by other except
statement bodies. If this solution is not enough to solve the problem, you can also do some more extreme processing, for example, find the C source code of the Python disk writing function, and raise a custom DiskFull
exception as needed . This last solution is not recommended, but it makes sense to know that this possibility exists when necessary.
14.2.8 Example: Abnormality during normal calculation
The most common use of exceptions is to handle errors, but they can also be very useful in situations that should be considered normal calculations. Imagine the problems that may be encountered in the implementation of spreadsheet programs. Like most spreadsheets, the program must be able to perform arithmetic operations involving multiple cells, and it must also allow cells to contain non-numeric values. In this kind of application, the contents of blank cells encountered during numerical calculations may be regarded as 0
values. Cells containing any other non-numeric strings may be considered invalid and expressed as Python None
values. Any calculation involving invalid values should return invalid values.
Let's first write a function to evaluate the string in a spreadsheet cell and return the appropriate value:
def cell_value(string):
try:
return float(string)
except ValueError:
if string == "":
return 0
else:
return None
Python's exception handling capabilities make this function very simple to write. In the try
block, the string in the cell is float
converted to a number with a built-in function, and the result is returned. If the parameter string cannot be converted to a number, the float
function throws ValueError
an exception. Then the exception handling code will catch the exception and return 0
or None
, depending on whether the parameter string is an empty string.
Sometimes it may be necessary None
to deal with the value during evaluation . The next step is to solve this problem. In a programming language without an exception mechanism, the conventional solution is to define a set of custom arithmetic evaluation functions, check whether the parameters are valid None
, and then use these custom functions to replace the built-in functions to perform all spreadsheet calculations. However, this process can be very time-consuming and error-prone. In fact, this is a self-built interpreter in the spreadsheet program, so it will reduce the running speed. This project uses another scheme. All spreadsheet formulas can actually be Python functions. The parameters of the function are the x and y coordinates of the cell being evaluated and the spreadsheet itself. Use standard Python arithmetic operators to calculate the result and cell_value
extract the necessary values from the spreadsheet. . You can define a named safe_apply
function, try
use the corresponding parameters in the block to complete the call of the formula, and return the calculation result according to whether the formula is successfully calculated or return None
:
def safe_apply(function, x, y, spreadsheet):
try:
return function(x, y, spreadsheet)
except TypeError:
return None
The above two changes are sufficient to add None
the concept of null ( ) to the semantics of the spreadsheet . If you do not use the exception mechanism to develop the above functions, it will be a very instructive exercise (the implication is that you can experience a considerable amount of work).
14.2.9 Applicable occasions for exceptions
Using exceptions to handle almost all errors is a natural solution. Often the error handling part will be added when the rest of the program is basically completed. Unfortunately, this is the case, but the exception mechanism is very good at writing this kind of post-error handling code in an easy-to-understand way. It is better to add more error handling code after the fact.
If there are calculation branches in the program that are obviously unsustainable, then there may be a large number of processing procedures to be discarded, then the exception mechanism will also be very useful. This is the case with the spreadsheet example. Other application scenarios include branch-and-bound algorithms and parsing algorithms.
Quick test: Will abnormal Python exceptions cause the program to abort?
Suppose you want to access the dictionary object
x
, if the key does not exist, that is, it is triggeredKeyError
, then returnNone
. How to write code to achieve this goal?
Hands-on question: Exception write code to create a custom
ValueTooLarge
, andx
raise it when the variable is greater than 1000.
This article is excerpted from "Python Quick Start (3rd Edition)"
This is a Python quick start book, written based on Python 3.6. The book is divided into 4 parts. The first part explains the basics of Python and gives a brief introduction to Python; the second part introduces the key points of Python programming, involving lists, tuples, sets, strings, dictionaries, flow control, functions, and modules And scope, file system, exceptions, etc.; the third part explains the advanced features of Python, involving classes and object-oriented, regular expressions, data types, ie objects, packages, Python libraries, etc.; the fourth part focuses on data processing, involving Data file processing, network data, data storage and data exploration, and finally related cases are given.
This book has a clear frame structure, reasonable content layout, a step-by-step explanation, and a large number of examples and exercises, so that readers can quickly learn and master Python. It is not only suitable for Python beginners to learn, but also suitable as a concise Python reference book for professional programmers.