python中异常处理
Welcome! In this article, you will learn how to handle exceptions in Python.
欢迎! 在本文中,您将学习如何在Python中处理异常。
In particular, we will cover:
特别是,我们将介绍:
Are you ready? Let's begin!
你准备好了吗? 让我们开始!
We will start with exceptions:
我们将从例外开始:
What are they?
它们是什么 ?
Why are they relevant?
它们为什么相关?
Why should you handle them?
你为什么要处理它们?
According to the Python documentation:
根据Python文档 :
Errors detected during execution are called exceptions and are not unconditionally fatal.
执行期间检测到的错误称为异常 ,并且不是无条件致命的。
Exceptions are raised when the program encounters an error during its execution. They disrupt the normal flow of the program and usually end it abruptly. To avoid this, you can catch them and handle them appropriately.
当程序在执行过程中遇到错误时,将引发异常。 它们破坏了程序的正常流程,通常会突然终止。 为避免这种情况,您可以抓住它们并进行适当处理。
You've probably seen them during your programming projects.
在编程项目中,您可能已经看过它们。
If you've ever tried to divide by zero in Python, you must have seen this error message:
如果您曾经尝试在Python中除以零,则必须看到以下错误消息:
>>> a = 5/0
Traceback (most recent call last):
File "", line 1, in
a = 5/0
ZeroDivisionError: division by zero
If you tried to index a string with an invalid index, you definitely got this error message:
如果您尝试使用无效的索引对字符串进行索引,则肯定会收到以下错误消息:
>>> a = "Hello, World"
>>> a[456]
Traceback (most recent call last):
File "", line 1, in
a[456]
IndexError: string index out of range
These are examples of exceptions.
这些是例外的例子。
There are many different types of exceptions, and they are all raised in particular situations. Some of the exceptions that you will most likely see as you work on your projects are:
异常类型很多,在特定情况下都会引发异常。 在处理项目时,您很可能会看到一些例外:
IndexError - raised when you try to index a list, tuple, or string beyond the permitted boundaries. For example:
IndexError-尝试索引超出允许范围的列表,元组或字符串时引发。 例如:
>>> num = [1, 2, 6, 5]
>>> num[56546546]
Traceback (most recent call last):
File "", line 1, in
num[56546546]
IndexError: list index out of range
KeyError - raised when you try to access the value of a key that doesn't exist in a dictionary. For example:
KeyError-当您尝试访问字典中不存在的键的值时引发。 例如:
>>> students = {"Nora": 15, "Gino": 30}
>>> students["Lisa"]
Traceback (most recent call last):
File "", line 1, in
students["Lisa"]
KeyError: 'Lisa'
NameError - raised when a name that you are referencing in the code doesn't exist. For example:
NameError-当您在代码中引用的名称不存在时引发。 例如:
>>> a = b
Traceback (most recent call last):
File "", line 1, in
a = b
NameError: name 'b' is not defined
TypeError - raised when an operation or function is applied to an object of an inappropriate type. For example:
TypeError-当操作或函数应用于不适当类型的对象时引发。 例如:
>>> (5, 6, 7) * (1, 2, 3)
Traceback (most recent call last):
File "", line 1, in
(5, 6, 7) * (1, 2, 3)
TypeError: can't multiply sequence by non-int of type 'tuple'
ZeroDivisionError - raised when you try to divide by zero.
ZeroDivisionError-尝试除以零时引发。
>>> a = 5/0
Traceback (most recent call last):
File "", line 1, in
a = 5/0
ZeroDivisionError: division by zero
Tips: To learn more about other types of built-in exceptions, please refer to this article in the Python Documentation.
s 提示:要了解有关其他类型的内置异常的更多信息,请参阅 Python文档中的本文 。
I'm sure that you must have noticed a general pattern in these error messages. Let's break down their general structure piece by piece:
我确定您一定已经注意到这些错误消息中的一般模式。 让我们逐一分解其总体结构:
First, we find this line (see below). A traceback is basically a list detailing the function calls that were made before the exception was raised.
首先,我们找到这条线(见下文)。 追溯基本上是一个列表,详细列出引发异常之前进行的函数调用。
The traceback helps you during the debugging process because you can analyze the sequence of function calls that resulted in the exception:
跟踪可以在调试过程中为您提供帮助,因为您可以分析导致异常的函数调用顺序:
Traceback (most recent call last):
Then, we see this line (see below) with the path to the file and the line that raised the exception. In this case, the path was the Python shell
然后,我们看到这一行(见下文)以及文件路径和引发异常的行。 在这种情况下,路径是Python shell
File "", line 1, in
a - 5/0
Tip: If the line that raised the exception belongs to a function,
提示:如果引发异常的行属于某个函数,则将
Finally, we see a descriptive message detailing the type of exception and providing additional information to help us debug the code:
最后,我们看到一条描述性消息,详细描述了异常类型并提供了其他信息来帮助我们调试代码:
NameError: name 'a' is not defined
You may ask: why would I want to handle exceptions? Why is this helpful for me? By handling exceptions, you can provide an alternative flow of execution to avoid crashing your program unexpectedly.
您可能会问:为什么我要处理异常? 为什么这对我有帮助? 通过处理异常,您可以提供另一种执行流程,以避免程序意外崩溃。
Imagine what would happen if a user who is working with your program enters an invalid input. This would raise an exception because an invalid operation was performed during the process.
想象一下,如果使用您的程序的用户输入了无效的输入,将会发生什么。 这将引发异常,因为在此过程中执行了无效的操作。
If your program doesn't handle this correctly, it will crash suddenly and the user will have a very disappointing experience with your product.
如果您的程序不能正确处理此问题,它将突然崩溃,并且用户将对您的产品感到非常失望。
But if you do handle the exception, you will be able to provide an alternative to improve the experience of the user.
但是,如果您确实处理了异常,则可以提供一种替代方法来改善用户体验。
Perhaps you could display a descriptive message asking the user to enter a valid input, or you could provide a default value for the input. Depending on the context, you can choose what to do when this happens, and this is the magic of error handling. It can save the day when unexpected things happen.
也许您可以显示一条描述性消息,要求用户输入有效输入,或者可以为输入提供默认值。 根据上下文,您可以选择发生这种情况时的处理方式,这就是错误处理的神奇之处。 它可以节省发生意外情况的时间。
Basically, when we handle an exception, we are telling the program what to do if the exception is raised. In that case, the "alternative" flow of execution will come to the rescue. If no exceptions are raised, the code will run as expected.
基本上,当我们处理异常时,我们告诉程序如果引发异常该怎么办。 在这种情况下,执行的“替代”流程将得到拯救。 如果没有引发异常,则代码将按预期运行。
Now that you know what exceptions are and why you should we handle them, we will start diving into the built-in tools that the Python languages offers for this purpose.
现在您知道了什么是异常以及为什么要处理它们,我们将开始深入研究Python语言为此目的提供的内置工具。
First, we have the most basic statement: try ... except.
首先,我们有最基本的声明:尝试...除外。
Let's illustrate this with a simple example. We have this small program that asks the user to enter the name of a student to display his/her age:
让我们用一个简单的例子来说明这一点。 我们有一个小程序,要求用户输入学生的姓名以显示他/她的年龄:
students = {"Nora": 15, "Gino": 30}
def print_student_age():
name = input("Please enter the name of the student: ")
print(students[name])
print_student_age()
Notice how we are not validating user input at the moment, so the user might enter invalid values (names that are not in the dictionary) and the consequences would be catastrophic because the program would crash if a KeyError is raised:
请注意,我们目前不验证用户输入,因此用户可能输入无效值(不在词典中的名称),后果将是灾难性的,因为如果引发KeyError,程序将崩溃:
# User Input
Please enter the name of the student: "Daniel"
# Error Message
Traceback (most recent call last):
File "", line 15, in
print_student_age()
File "", line 13, in print_student_age
print(students[name])
KeyError: '"Daniel"'
We can handle this nicely using try ... except. This is the basic syntax:
我们可以使用try ...很好地解决这个问题。 这是基本语法:
In our example, we would add the try ... except statement within the function. Let's break this down piece by piece:
在我们的示例中,我们将在函数中添加try ... except语句。 让我们逐一分解:
students = {"Nora": 15, "Gino": 30}
def print_student_age():
while True:
try:
name = input("Please enter the name of the student: ")
print(students[name])
break
except:
print("This name is not registered")
print_student_age()
If we "zoom in", we see the try ... except statement:
如果我们“放大”,则会看到try ...除外语句:
try:
name = input("Please enter the name of the student: ")
print(students[name])
break
except:
print("This name is not registered")
Note: This code is contained within a while loop to continue asking for user input if the value is invalid. This is an example:
注意:这段代码包含在while循环中,以继续询问用户输入值是否无效。 这是一个例子:
Please enter the name of the student: "Lulu"
This name is not registered
Please enter the name of the student:
This is great, right? Now we can continue asking for user input if the value is invalid.
太好了吧? 现在,我们可以继续要求用户输入值是否无效。
At the moment, we are handling all possible exceptions with the same except clause. But what if we only want to handle a specific type of exception? Let's see how we could do this.
目前,我们正在使用相同的except子句处理所有可能的异常。 但是,如果我们只想处理特定类型的异常该怎么办? 让我们看看如何做到这一点。
Since not all types of exceptions are handled in the same way, we can specify which exceptions we would like to handle with this syntax:
由于并非所有类型的异常都以相同的方式处理,因此我们可以使用以下语法指定要处理的异常:
This is an example. We are handling the ZeroDivisionError exception in case the user enters zero as the denominator:
这是一个例子。 如果用户输入零作为分母,我们将处理ZeroDivisionError异常:
def divide_integers():
while True:
try:
a = int(input("Please enter the numerator: "))
b = int(input("Please enter the denominator: "))
print(a / b)
except ZeroDivisionError:
print("Please enter a valid denominator.")
divide_integers()
This would be the result:
结果如下:
# First iteration
Please enter the numerator: 5
Please enter the denominator: 0
Please enter a valid denominator.
# Second iteration
Please enter the numerator: 5
Please enter the denominator: 2
2.5
We are handling this correctly. But... if another type of exception is raised, the program will not handle it gracefully.
我们正在正确处理此问题。 但是...如果引发了另一种类型的异常,则程序将无法正常处理它。
Here we have an example of a ValueError because one of the values is a float, not an int:
这里有一个ValueError的示例,因为其中一个值是浮点数,而不是整数:
Please enter the numerator: 5
Please enter the denominator: 0.5
Traceback (most recent call last):
File "", line 53, in
divide_integers()
File "", line 47, in divide_integers
b = int(input("Please enter the denominator: "))
ValueError: invalid literal for int() with base 10: '0.5'
We can customize how we handle different types of exceptions.
我们可以自定义如何处理不同类型的异常。
To do this, we need to add multiple except
clauses to handle different types of exceptions differently.
为此,我们需要添加多个except
子句以不同方式处理不同类型的异常。
According to the Python Documentation:
根据Python文档 :
A try statement may have more than one except clause, to specify handlers for different exceptions. At most one handler will be executed.
一个try语句可能具有多个except子句 ,以指定不同异常的处理程序。 最多将执行一个处理程序 。
In this example, we have two except clauses. One of them handles ZeroDivisionError and the other one handles ValueError, the two types of exceptions that could be raised in this try block.
在这个例子中,我们有两个except子句。 其中一个处理ZeroDivisionError,另一个处理ValueError,这是在try块中可能引发的两种类型的异常。
def divide_integers():
while True:
try:
a = int(input("Please enter the numerator: "))
b = int(input("Please enter the denominator: "))
print(a / b)
except ZeroDivisionError:
print("Please enter a valid denominator.")
except ValueError:
print("Both values have to be integers.")
divide_integers()
Tip: You have to determine which types of exceptions might be raised in the try block to handle them appropriately.
提示:您必须确定在try块中可能会引发哪些异常类型,以适当地处理它们。
You can also choose to handle different types of exceptions with the same except clause.
您还可以选择使用相同的except子句来处理不同类型的异常。
According to the Python Documentation:
根据Python文档 :
An except clause may name multiple exceptions as a parenthesized tuple.
except子句可以将多个异常命名为带括号的元组。
This is an example where we catch two exceptions (ZeroDivisionError and ValueError) with the same except
clause:
这是一个示例,其中我们使用相同的except
子句捕获了两个异常(ZeroDivisionError和ValueError):
def divide_integers():
while True:
try:
a = int(input("Please enter the numerator: "))
b = int(input("Please enter the denominator: "))
print(a / b)
except (ZeroDivisionError, ValueError):
print("Please enter valid integers.")
divide_integers()
The output would be the same for the two types of exceptions because they are handled by the same except clause:
这两种异常的输出将相同,因为它们由相同的except子句处理:
Please enter the numerator: 5
Please enter the denominator: 0
Please enter valid integers.
Please enter the numerator: 0.5
Please enter valid integers.
Please enter the numerator:
An interesting aspect of exception handling is that if an exception is raised in a function that was previously called in the try clause of another function and the function itself does not handle it, the caller will handle it if there is an appropriate except clause.
异常处理的一个有趣方面是,如果先前在另一个函数的try子句中调用的函数中引发了异常,而该函数本身不处理该异常,则在存在适当的except子句的情况下,调用方将对其进行处理。
According to the Python Documentation:
根据Python文档 :
Exception handlers don’t just handle exceptions if they occur immediately in the try clause, but also if they occur inside functions that are called (even indirectly) in the try clause.
如果异常处理程序立即在try子句中发生,则异常处理程序不仅会处理异常,而且如果它们在try子句中被调用(甚至是间接调用)的函数中发生 ,异常处理程序也不例外。
Let's see an example to illustrate this:
让我们看一个例子来说明这一点:
def f(i):
try:
g(i)
except IndexError:
print("Please enter a valid index")
def g(i):
a = "Hello"
return a[i]
f(50)
We have the f
function and the g
function. f
calls g
in the try clause. With the argument 50, g
will raise an IndexError because the index 50 is not valid for the string a.
我们有f
函数和g
函数。 f
在try子句中调用g
。 使用参数50时, g
将引发IndexError,因为索引50对字符串a无效。
But g
itself doesn't handle the exception. Notice how there is no try ... except statement in the g
function. Since it doesn't handle the exception, it "sends" it to f
to see if it can handle it, as you can see in the diagram below:
但是g
本身不处理异常。 注意g
函数中除了try语句外,没有try...。 由于它不处理异常,因此将其“发送”给f
以查看其是否可以处理它,如下图所示:
Since f does know how to handle an IndexError, the situation is handled gracefully and this is the output:
由于f 确实知道如何处理IndexError,因此可以很好地处理这种情况,这是输出:
Please enter a valid index
Note: If f
had not handled the exception, the program would have ended abruptly with the default error message for an IndexError.
注意:如果f
没有处理异常,则该程序将突然终止,并显示IndexError的默认错误消息。
Exceptions are objects in Python, so you can assign the exception that was raised to a variable. This way, you can print the default description of the exception and access its arguments.
异常是Python中的对象,因此您可以将引发的异常分配给变量。 这样,您可以打印异常的默认描述并访问其参数。
According to the Python Documentation:
根据Python文档 :
The except clause may specify a variable after the exception name. The variable is bound to an exception instance with the arguments stored in instance.args.
except子句可以在异常名称后指定一个变量 。 该变量通过存储在instance.args中的参数绑定到异常实例。
Here we have an example (see below) were we assign the instance of ZeroDivisionError
to the variable e
. Then, we can use this variable within the except clause to access the type of the exception, its message, and arguments.
这里有一个示例(请参见下文),我们将ZeroDivisionError
的实例分配给变量e
。 然后,我们可以在except子句中使用此变量来访问异常的类型,其消息和参数。
def divide_integers():
while True:
try:
a = int(input("Please enter the numerator: "))
b = int(input("Please enter the denominator: "))
print(a / b)
# Here we assign the exception to the variable e
except ZeroDivisionError as e:
print(type(e))
print(e)
print(e.args)
divide_integers()
The corresponding output would be:
相应的输出为:
Please enter the numerator: 5
Please enter the denominator: 0
# Type
# Message
division by zero
# Args
('division by zero',)
Tip: If you are familiar with special methods, according to the Python Documentation: "for convenience, the exception instance defines __str__()
so the arguments can be printed directly without having to reference .args
."
提示:如果您熟悉特殊方法,请参阅Python文档 :“为方便起见,异常实例定义了__str__()
因此可以直接打印参数而不必引用.args
。”
The else
clause is optional, but it's a great tool because it lets us execute code that should only run if no exceptions were raised in the try clause.
else
子句是可选的,但这是一个很好的工具,因为它使我们能够执行仅在try子句中未引发任何异常的情况下才能运行的代码。
According to the Python Documentation:
根据Python文档 :
The
try
…except
statement has an optional else clause, which, when present, must follow all except clauses. It is useful for code that must be executed if the try clause does not raise an exception.
try
…except
语句具有可选的 else子句 ,该子句在存在时必须遵循所有except子句。 这对于try子句未引发异常的必须执行的代码很有用。
Here is an example of the use of the else
clause:
这是一个使用else
子句的示例:
def divide_integers():
while True:
try:
a = int(input("Please enter the numerator: "))
b = int(input("Please enter the denominator: "))
result = a / b
except (ZeroDivisionError, ValueError):
print("Please enter valid integers. The denominator can't be zero")
else:
print(result)
divide_integers()
If no exception are raised, the result is printed:
如果未引发任何异常,则打印结果:
Please enter the numerator: 5
Please enter the denominator: 5
1.0
But if an exception is raised, the result is not printed:
但是,如果引发异常,则不会打印结果:
Please enter the numerator: 5
Please enter the denominator: 0
Please enter valid integers. The denominator can't be zero
Tip: According to the Python Documentation:
提示:根据Python文档 :
The use of the
else
clause is better than adding additional code to thetry
clause because it avoids accidentally catching an exception that wasn’t raised by the code being protected by thetry
…except
statement.使用
else
子句比向try
子句添加其他代码更好,因为它避免了意外捕获try
...except
语句所保护的代码未引发的异常。
The finally clause is the last clause in this sequence. It is optional, but if you include it, it has to be the last clause in the sequence. The finally
clause is always executed, even if an exception was raised in the try clause.
finally子句是此序列中的最后一个子句。 它是可选的 ,但是如果包含它,它必须是序列中的最后一个子句。 即使try子句中引发了异常, finally
子句也总是执行。
According to the Python Documentation:
根据Python文档 :
If a
finally
clause is present, thefinally
clause will execute as the last task before thetry
statement completes. Thefinally
clause runs whether or not thetry
statement produces an exception.如果存在
finally
子句,则try
子句完成之前,finally
子句将作为最后一个任务执行。 无论try
语句是否产生异常 ,finally
子句都会运行。
The finally clause is usually used to perform "clean-up" actions that should always be completed. For example, if we are working with a file in the try clause, we will always need to close the file, even if an exception was raised when we were working with the data.
finally子句通常用于执行应始终完成的“清理”操作。 例如,如果我们在try子句中使用文件,则即使在使用数据时引发了异常,也将始终需要关闭文件。
Here is an example of the finally clause:
这是finally子句的示例:
def divide_integers():
while True:
try:
a = int(input("Please enter the numerator: "))
b = int(input("Please enter the denominator: "))
result = a / b
except (ZeroDivisionError, ValueError):
print("Please enter valid integers. The denominator can't be zero")
else:
print(result)
finally:
print("Inside the finally clause")
divide_integers()
This is the output when no exceptions were raised:
这是没有引发异常时的输出:
Please enter the numerator: 5
Please enter the denominator: 5
1.0
Inside the finally clause
This is the output when an exception was raised:
这是引发异常时的输出:
Please enter the numerator: 5
Please enter the denominator: 0
Please enter valid integers. The denominator can't be zero
Inside the finally clause
Notice how the finally
clause always runs.
请注意finally
子句始终如何运行。
Important: remember that the else
clause and the finally
clause are optional, but if you decide to include both, the finally clause has to be the last clause in the sequence.
重要:请记住, else
子句和finally
子句是可选的,但是如果决定同时包含这两个子句,则finally子句必须是序列中的最后一个子句。
Now that you know how to handle exceptions in Python, I would like to share with you this helpful tip: you can also choose when to raise exceptions in your code.
既然您知道如何使用Python处理异常,那么我想与您分享这个有用的提示: 您还可以选择何时在代码中引发异常。
This can be helpful for certain scenarios. Let's see how you can do this:
这在某些情况下可能会有所帮助。 让我们看看如何做到这一点:
This line will raise a ValueError with a custom message.
此行将引发带有自定义消息的ValueError。
Here we have an example (see below) of a function that prints the value of the items of a list or tuple, or the characters in a string. But you decided that you want the list, tuple, or string to be of length 5. You start the function with an if statement that checks if the length of the argument data
is 5. If it isn't, a ValueError exception is raised:
在这里,我们有一个函数示例(见下文),该函数可打印列表或元组的项目值或字符串中的字符。 但是您决定要使列表,元组或字符串的长度为5。使用if语句启动该函数,该语句检查参数data
的长度是否为5。如果不是,则会引发ValueError异常。 :
def print_five_items(data):
if len(data) != 5:
raise ValueError("The argument must have five elements")
for item in data:
print(item)
print_five_items([5, 2])
The output would be:
输出为:
Traceback (most recent call last):
File "", line 122, in
print_five_items([5, 2])
File "", line 117, in print_five_items
raise ValueError("The argument must have five elements")
ValueError: The argument must have five elements
Notice how the last line displays the descriptive message:
注意最后一行如何显示描述性消息:
ValueError: The argument must have five elements
You can then choose how to handle the exception with a try ... except statement. You could add an else clause and/or a finally clause. You can customize it to fit your needs.
然后,您可以使用try ... except语句选择如何处理异常。 您可以添加else子句和/或finally子句。 您可以对其进行自定义以满足您的需求。
Exceptions
例外情况
Handling Exceptions
处理异常
Defining Clean-up Actions
定义清理措施
I hope you enjoyed reading my article and found it helpful. Now you have the necessary tools to handle exceptions in Python and you can use them to your advantage when you write Python code. Check out my online courses. You can follow me on Twitter.
我希望您喜欢阅读我的文章并发现对您有所帮助。 现在,您已经拥有处理Python中异常的必要工具,并且在编写Python代码时可以利用它们发挥自己的优势。 查看我的在线课程 。 您可以在Twitter上关注我。
You may enjoy my other freeCodeCamp /news articles:
您可能会喜欢我的其他freeCodeCamp / news文章:
The @property Decorator in Python: Its Use Cases, Advantages, and Syntax
Python中的@property Decorator:其用例,优点和语法
Data Structures 101: Graphs — A Visual Introduction for Beginners
数据结构101:图-初学者的直观介绍
Data Structures 101: Arrays — A Visual Introduction for Beginners
数据结构101:数组-初学者的直观介绍
翻译自: https://www.freecodecamp.org/news/exception-handling-python/
python中异常处理