geekdoc-python-zh/docs/pythonlibrary/python-101-exception-handli...

253 lines
9.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Python 101 -异常处理
> 原文:<https://www.blog.pythonlibrary.org/2020/06/17/python-101-exception-handling-2/>
开发软件是一项艰苦的工作。为了让你的软件变得更好,你的应用程序需要保持工作,即使发生了意想不到的事情。例如,假设您的应用程序需要从互联网上下载信息。如果使用您的应用程序的人失去了互联网连接,会发生什么?
另一个常见的问题是,如果用户输入了无效的输入,该怎么办。或者试图打开应用程序不支持的文件。
所有这些情况都可以使用 Python 内置的异常处理功能来处理,这些功能通常被称为`try`和`except`语句。
在本文中,您将了解到:
* 常见例外
* 处理异常
* 引发异常
* 检查异常对象
* 使用`finally`语句
* 使用`else`语句
让我们从了解一些最常见的异常开始。
### 最常见的例外
Python 支持许多不同的异常。当你第一次开始使用这种语言时,你可能会看到下面的一些:
* 所有其他异常所基于的基础异常
* `AttributeError` -当属性引用或赋值失败时引发。
* `ImportError` -当导入语句找不到模块定义或当...导入找不到要导入的名称。
* `ModuleNotFoundError`-import error 的一个子类,当模块无法定位时,由 import 引发
* `IndexError` -当序列下标超出范围时引发。
* `KeyError` -在现有键集中找不到映射(字典)键时引发。
* `KeyboardInterrupt` -当用户点击中断键时触发(通常为`Control-C`或`Delete`)。
* `NameError` -找不到本地或全局名称时引发。
* `OSError` -当函数返回与系统相关的错误时引发。
* `RuntimeError` -当检测到不属于任何其他类别的错误时引发。
* `SyntaxError` -当解析器遇到语法错误时引发。
* `TypeError` -当一个操作或函数被应用到一个不合适类型的对象时引发。关联的值是一个字符串,给出关于类型不匹配的详细信息。
* `ValueError` -当内置操作或函数接收到类型正确但值不正确的参数,并且这种情况没有通过更精确的异常(如 IndexError)来描述时引发。
* `ZeroDivisionError`—当除法或模运算的第二个参数为零时引发。
有关内置异常的完整列表,您可以在此处查看 Python 文档:
* [https://docs.python.org/3/library/exceptions.html](https://docs.python.org/3/library/exceptions.html)。
现在让我们来看看当一个异常发生时,实际上如何处理它。
### 处理异常
Python 提供了一种特殊的语法,可以用来捕捉异常。它被称为`try/except`语句。
这是您将用于捕捉异常的基本形式:
```py
try:
# Code that may raise an exception goes here
except ImportError:
# Code that is executed when an exception occurs
```
您将您认为可能有问题的代码放在`try`块中。这可能是打开文件的代码,也可能是从用户那里获得输入的代码。第二个模块被称为`except`模块。这段代码只有在出现`ImportError`时才会被执行。
当你在没有指定异常类型的情况下编写`except`时,它被称为**裸异常**。不建议使用这些方法:
```py
try:
with open('example.txt') as file_handler:
for line in file_handler:
print(line)
except:
print('An error occurred')
```
创建一个空的异常是不好的做法,因为你不知道你正在捕捉什么类型的异常。这使得找出你做错了什么变得更加困难。如果您将异常类型缩小到您期望的类型,那么意外的类型实际上会使您的应用程序崩溃,并显示有用的消息。
此时,您可以决定是否要捕捉其他条件。
假设您想要捕获多个异常。有一种方法可以做到:
```py
try:
with open('example.txt') as file_handler:
for line in file_handler:
print(line)
import something
except OSError:
print('An error occurred')
except ImportError:
print('Unknown import!')
```
这个异常处理程序将捕获两种类型的异常:`OSError`和`ImportError`。如果发生另一种类型的异常,这个处理程序将不会捕捉到它,您的代码将会停止。
通过这样做,您可以将上面的代码重写得简单一点:
```py
try:
with open('example.txt') as file_handler:
for line in file_handler:
print(line)
import something
except (OSError, ImportError):
print('An error occurred')
```
当然,通过创建异常元组,这将混淆哪个异常已经发生。换句话说,这段代码使得知道发生了哪个异常变得更加困难。
### 引发异常
在你捕捉到一个异常后你会怎么做?你有几个选择。您可以像前面的例子一样打印出一条消息。您还可以将消息记录到日志文件中。或者,如果您知道该异常需要停止应用程序的执行,您可以重新引发该异常。
引发异常是强制异常发生的过程。你在特殊情况下提出例外。例如,如果应用程序进入不良状态,您可能会引发一个异常。在已经处理了异常之后,您还会倾向于引发异常。
您可以使用 Python 的内置`raise`语句来引发异常:
```py
try:
raise ImportError
except ImportError:
print('Caught an ImportError')
```
当您引发异常时,您可以让它打印出一条自定义消息:
```py
>>> raise Exception('Something bad happened!')
Traceback (most recent call last):
Python Shell, prompt 1, line 1
builtins.Exception: Something bad happened!
```
如果不提供消息,则异常如下所示:
```py
>>> raise Exception
Traceback (most recent call last):
Python Shell, prompt 2, line 1
builtins.Exception:
```
现在让我们来了解一下异常对象!
### 检查异常对象
当异常发生时Python 会创建一个异常对象。您可以通过使用`as`语句将异常对象赋给一个变量来检查它:
```py
>>> try:
... raise ImportError('Bad import')
... except ImportError as error:
... print(type(error))
... print(error.args)
... print(error)
...
<class 'ImportError'>
('Bad import',)
Bad import
```
在本例中,您将`ImportError`对象分配给了`error`。现在您可以使用 Python 的`type()`函数来了解它是哪种异常。这将允许您解决本文前面提到的问题,当您有一个异常元组,但您不能立即知道您捕获了哪个异常。
如果您想更深入地调试异常,您应该查找 Python 的`traceback`模块。
### 使用`finally`语句
除了`try`和`except`,还有更多关于`try/except`的陈述。您也可以向它添加一个`finally`语句。`finally`语句是一个代码块,即使在`try`语句中出现异常,它也会一直运行。
您可以使用`finally`语句进行清理。例如,您可能需要关闭数据库连接或文件句柄。为此,您可以将代码包装在一个`try/except/finally`语句中。
让我们看一个人为的例子:
```py
>>> try:
... 1 / 0
... except ZeroDivisionError:
... print('You can not divide by zero!')
... finally:
... print('Cleaning up')
...
You can not divide by zero!
Cleaning up
```
这个例子演示了如何处理`ZeroDivisionError`异常以及添加清理代码。
但是您也可以完全跳过`except`语句,而是创建一个`try/finally`:
```py
>>> try:
... 1/0
... finally:
... print('Cleaning up')
...
Cleaning upTraceback (most recent call last):
Python Shell, prompt 6, line 2
builtins.ZeroDivisionError: division by zero
```
这次您不处理`ZeroDivisionError`异常,但是`finally`语句的代码块仍然运行。
### 使用`else`语句
还有一个语句可以用于 Python 的异常处理,那就是`else`语句。当没有异常时,可以使用`else`语句来执行代码。
这里有一个例子:
```py
>>> try:
... print('This is the try block')
... except IOError:
... print('An IOError has occurred')
... else:
... print('This is the else block')
...
This is the try block
This is the else block
```
在这段代码中,没有发生异常,所以`try`块和`else`块都运行。
让我们试着提高一个`IOError`,看看会发生什么:
```py
>>> try:
... raise IOError
... print('This is the try block')
... except IOError:
... print('An IOError has occurred')
... else:
... print('This is the else block')
...
An IOError has occurred
```
由于出现异常,只有`try`和`except`模块运行。注意,`try`块在`raise`语句处停止运行。它根本没有到达`print()`函数。一旦出现异常,下面的所有代码都会被跳过,直接进入异常处理代码。
### 包扎
现在您知道了使用 Python 内置异常处理的基本知识。在本文中,您了解了以下主题:
* 常见例外
* 处理异常
* 引发异常
* 检查异常对象
* 使用`finally`语句
* 使用`else`语句
学习如何有效地捕捉异常需要练习。一旦你学会了如何捕捉异常,你将能够强化你的代码,使它以一种更好的方式工作,即使发生了意想不到的事情。
### 相关阅读
* Python 101: [条件语句](https://www.blog.pythonlibrary.org/2020/04/29/python-101-conditional-statements/)
* Python 101: [学习循环](https://www.blog.pythonlibrary.org/2020/05/27/python-101-learning-about-loops/)
* Python 101: [了解集合](https://www.blog.pythonlibrary.org/2020/04/28/python-101-learning-about-sets/)