访问量: 223 次浏览

Python 程序一旦遇到错误就会终止。 在 Python 中, 错误可以是语法错误或异常。 在本教程中, 您将了解什么是异常以及它与语法错误有何不同。 之后将学习如何引发异常和做出断言, 了解可以在 try… 块中使用的所有与异常相关的关键字, except 用于微调如何处理 Python 异常。
学习如何:
raiseasserttry 使用 and 处理异常 exceptelse 使用和微调异常处理 finally通过演练处理与平台相关的异常的实际示例, 将了解这些关键字。 最后还将学习如何创建自己的自定义 Python 异常。
当解析器检测到不正确的语句时, 就会出现语法错误。 观察以下示例:
Python 回溯
>>> print(0 / 0))
File "<stdin>", line 1
print(0 / 0))
^
SyntaxError: unmatched ')'
箭头指示解析器在何处遇到语法错误。 此外,错误消息还提示出了什么问题。 在此示例中,括号过多。 删除它并再次运行代码:
Python
>>> print(0 / 0)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ZeroDivisionError: division by zero
这次,遇到了异常错误。 只要语法正确的 Python 代码导致错误, 就会发生这种类型的错误。 消息的最后一行指示您遇到的异常错误类型。
Python 不只是写异常错误, 而是详细说明它遇到的异常错误类型。 在本例中,它是一个ZeroDivisionError.Python 带有各种内置异常以及创建用户定义异常的可能性。
在某些情况下,如果发生某种情况, 可能希望通过引发异常来停止程序, 可使用关键字来做到这一点 raise :

甚至可以使用自定义消息来补充该语句。 假设正在编写一个小型玩具程序, 该程序只期望5以内的数字。 当出现不需要的情况时, 可以引发错误:
Python
number = 10
if number > 5:
raise Exception(f"The number should not exceed 5. ({number=})")
print(number)
程序停止并在终端或REPL上显示异常, 提供有关问题所在的有用线索。 请注意,最终的调用 print() 从未执行, 因为 Python 在到达该代码行之前引发了异常。
使用 raise 关键字, 可在 Python 中引发任何异常对象, 并在发生不需要的情况时停止程序。
assert在继续使用Python中使用 try...except 块处理异常的最常见方法之前, 将快速浏览一下与其他异常稍有不同的异常。
Python 提供了一种特定的异常类型, 只应在开发过程中调试程序时使用该异常类型。 这个例外是 AssertionError . 它 AssertionError 很特别, 因为不应该自己使用来引发它 raise 。
相反,可使用关键字来 assert 检查是否满足条件, 并让 PythonAssertionError 在不满足条件时引发 。
程序应该仅在某些条件满足时尝试运行。 如果 Python 检查你的断言并发现条件是 True , 程序可以继续进行。 如果条件为 False , 那么程序将引发 AssertionError 异常并立即停止:

重新访问上一节 low.py 中的小脚本。 目前,当不满足特定条件时, 会显式引发异常:
number = 1
if number > 5:
raise Exception(f"The number should not exceed 5. ({number=})")
print(number)
假设将为生产系统安全地处理此约束, 可将此条件语句替换为断言, 以便在开发过程中快速保留此健全性检查:
number = 1
assert (number < 5), f"The number should not exceed 5. ({number=})"
print(number)
如果 number 的程序中的如下5, 则断言通过并且脚本继续执行下一行代码。 但是,如果设置 number 的值高于5(例如), 10则断言的结果将是 False :
number = 10
assert (number < 5), f"The number should not exceed 5. ({number=})"
print(number)
在这种情况下, Python 会引发一个 AssertionError 包含传递的消息, 并结束程序执行:
$ python low.py
Traceback (most recent call last):
File "./low.py", line 2, in <module>
assert (number < 5), f"The number should not exceed 5. ({number=})"
^^^^^^^^^^
AssertionError: The number should not exceed 5. (number=10)
在此示例中,引发 AssertionError 异常是程序要做的最后一件事。 然后该程序将停止并且不会继续。 断言后面的调用 print() 将不会执行。
当在开发过程中调试程序时, 以这种方式使用断言会很有帮助, 因为将断言添加到代码中可以非常快速且直接。
但是,不应该依赖断言来捕获生产中程序的关键运行条件。 -O 这是因为当使用和 -OO 命令行选项在优化模式下运行 Python 时, Python 会全局禁用断言:
$ python -O low.py
10
在程序的本次运行中,使用了-O命令行选项, 该选项删除了所有 assert 语句。 因此,脚本一直运行到最后并显示了一个高得可怕的数字!
注意:或者也可以通过 PYTHONOPTIMIZE 环境变量禁用断言。
在生产中, Python 代码可能会使用这种优化模式运行, 这意味着断言并不是处理生产代码中运行时错误的可靠方法。 当调试代码时, 它们可以是快速且有用的帮助者, 但永远不应该使用断言来为程序设置关键约束。
如果在上述情况 low.py 下确实会失败, 那么最好坚持引发异常。 然而,有时可能不希望程序在遇到异常时失败, 那么应该如何处理这些情况呢?number5
若当数字大于5时,low.py 确实会失败, 那个么最好坚持引发异常。 然而,有时可能不希望程序在遇到异常时失败, 那么应该如何处理这些情况呢?
try 和 except 块处理异常在 Python 中, 可使用 tryandexcept 块来捕获和处理异常。 Python 将执行该 try 语句后面的代码作为程序的正常部分。 该语句后面的代码 except 是程序对前面 try 子句中的任何异常的响应:

正如之前所见, 当语法正确的代码遇到错误时, Python 将引发异常错误。 如果不处理这个异常错误, 程序就会崩溃。 在该 except 子句中, 可以确定程序应如何响应异常。
下面的函数可以帮助理解 tryandexcept 块:
def linux_interaction():
import sys
if "linux" not in sys.platform:
raise RuntimeError("Function can only run on Linux systems.")
print("Doing Linux things.")
只能 linux_interaction() 在 Linux 系统上运行。 RuntimeError 如果在 Linux 以外的操作系统上调用 Python , 它将引发异常。
注意:选择正确的异常类型有时可能很棘手。 Python 附带了许多分层相关的内置异常, 因此如果您浏览文档, 很可能会找到合适的异常。
Python 甚至将一些异常分组, 例如应用于指示警告条件的警告, 以及 Python 根据系统错误代码引发的操作系统异常。
如果仍然没有找到合适的异常, 那么可创建自定义异常。 try 可以通过添加以下代码来赋予函数 a :
# ...
try:
linux_interaction()
except:
pass
在这里处理错误的方法是分发一个 pass . 如果在 macOS 或 Windows 计算机上运行此代码, 将得到以下输出:
$ python linux_interaction.py
没有得到任何回应。 这里的好处是程序没有崩溃。 但是让发生的异常默默地过去是不好的做法, 至少应该始终了解并记录运行代码时是否发生某种类型的异常。
为此,可以更改 pass 为生成信息性消息的内容:
# ...
try:
linux_interaction()
except:
print("Linux function wasn't executed.")
现在,当在 macOS 或 Windows 计算机上执行此代码时, 将看到 except 块中的消息打印到控制台:
$ python linux_interaction.py
Linux function wasn't executed.
当运行此函数的程序中发生异常时, 程序将继续运行并通知您函数调用不成功的事实。
没有看到 Python 由于函数调用而引发的错误类型, 为了准确地了解出了什么问题, 需要捕获该函数引发的错误。 以下代码是捕获 RuntimeError 该消息并将其输出到屏幕的示例:
# ...
try:
linux_interaction()
except RuntimeError as error:
print(error)
print("The linux_interaction() function wasn't executed.")
在该 except 子句中, 将分配 RuntimeError 给临时变量 error(通常也称为临时 err 变量), 以便可以访问缩进块中的异常对象。 在本例中,将打印对象的字符串表示形式, 它对应于附加到对象的错误消息。
在 macOS 或 Windows 计算机上运行此函数会输出以下内容:
$ python linux_interaction.py
Function can only run on Linux systems.
The linux_interaction() function wasn't executed.
第一条消息是 RuntimeError, 通知 Python 只能在 Linux 机器上执行该函数。 第二条消息告知哪个函数未执行。
在上面的示例中, 调用了自己编写的函数, 当执行该函数时, 捕获了 RuntimeError 异常并将其打印到屏幕上。 这是打开文件并使用内置异常的另一个示例:
try:
with open("file.log") as file:
read_data = file.read()
except:
print("Couldn't open file.log")
如果 file.log 不存在, 则该代码块将输出以下内容:
$ python open_file.py
Couldn't open file.log
这是一条信息性消息,程序仍将继续运行。 然而 except 块当前将捕获任何异常, 无论这是否与无法打开文件有关。 如果看到此消息, 即使 Python 引发了完全不相关的异常, 也可能会陷入混乱。
因此,在处理异常时最好是具体化。
在 Python 文档中, 可看到在这种情况下可以引发一些内置异常, 例如:
当请求文件或目录但不存在时引发, 对应于 errno ENOENT 。
当想要处理 Python 找不到所请求的文件的情况。 要捕获此类异常并将其打印到屏幕上, 可以使用以下代码:
try:
with open("file.log") as file:
read_data = file.read()
except FileNotFoundError as fnf_error:
print(fnf_error)
在这种情况下,如果 file.log 不存在, 则输出将如下:
$ python open_file.py
[Errno 2] No such file or directory: 'file.log'
子句中可以有多个函数调用 try , 并预期捕获各种异常。 这里需要注意的是, 子句中的代码 try 一旦遇到任何异常就会停止。
警告:当使用裸 except 子句时, Python 会捕获继承自的任何异常 Exception- 这是大多数内置异常! 捕获父类 Exception 会隐藏所有错误, 甚至是那些根本没有预料到的错误。 这就是为什么应该避免 except 在 Python 程序中使用裸子句。
相反,需要引用要捕获和处理的特定异常类。
看下面的代码。在这里, 首先调用 linux_interaction() 然后尝试打开文件:
# ...
try:
linux_interaction()
with open("file.log") as file:
read_data = file.read()
except FileNotFoundError as fnf_error:
print(fnf_error)
except RuntimeError as error:
print(error)
print("Linux linux_interaction() function wasn't executed.")
如果在 macOS 或 Windows 计算机上运行此代码, 将看到以下内容:
$ python linux_interaction.py
Function can only run on Linux systems.
Linux linux_interaction() function wasn't executed
在该 try 子句中,立即遇到了异常, 并且没有到达尝试打开的部分 file.log 。 现在看看如果文件不存在, 在 Linux 机器上运行代码时会发生什么:
$ python linux_interaction.py
[Errno 2] No such file or directory: 'file.log'
请注意,如果像上面那样处理特定的异常, 那么子句的顺序except并不重要。 关键在于 Python 首先引发哪个异常。 一旦 Python 引发异常, 它就会从上到下检查 except 子句并执行它找到的第一个匹配的子句。
try 以下是有关使用 Python ...语句的关键要点 except :
try 子句,直到遇到第一个异常为止。except 子句(异常处理程序)内,可确定程序如何响应异常。except 子句,因为它们可能隐藏意外的异常。try 虽然与 一起使用 except 可能是会遇到的最常见的错误处理, 但可以采取更多措施来微调程序对异常的响应。
else可以使用 Python 的 else 语句来指示程序仅在没有异常的情况下执行特定的代码块:

看下面的示例:
# ...
try:
linux_interaction()
except RuntimeError as error:
print(error)
else:
print("Doing even more Linux things.")
如果要在 Linux 系统上运行此代码, 则输出将如下所示:
Shell
$ python linux_interaction.py
Doing Linux things.
Doing even more Linux things.
由于程序没有遇到任何异常, Python 执行了子句中的代码 else 。 但是,如果在 macOS 或 Windows 系统上运行此代码, 则会得到不同的输出:
Shell
$ python linux_interaction.py
Function can only run on Linux systems.
该 linux_interaction() 函数提出了一个 RuntimeError 。 已经处理了异常, 因此程序不会崩溃, 而是将异常消息打印到控制台。 但是,嵌套在该子句下的代码 else 不会执行, 因为 Python 在执行过程中遇到了异常。
请注意, 这样构造代码与在 try…except 块的上下文之外添加对 print()的调用不同:
Python
# ...
try:
linux_interaction()
except RuntimeError as error:
print(error)
print("Doing even more Linux things.")
如果没有将调用嵌套 print() 在该 else 子句下, 那么即使 Python 遇到 RuntimeError 在 except 上面的块中处理的内容, 它也会执行。在 Linux 系统上, 输出是相同的,但在 macOS 或 Windows 上, 将得到以下输出:
Shell
$ python linux_interaction.py
Function can only run on Linux systems.
Doing even more Linux things.
在 else 子句下嵌套代码可以确保只有当 Python 在执行 try…except 块时没有遇到任何异常时, 它才会运行。
还可以在子句中创建一个嵌套的 try…except 块 else 并捕获可能的异常:
# ...
try:
linux_interaction()
except RuntimeError as error:
print(error)
else:
try:
with open("file.log") as file:
read_data = file.read()
except FileNotFoundError as fnf_error:
print(fnf_error)
如果要在 Linux 计算机上执行此代码, 那么将得到以下结果:
Shell
$ python linux_interaction.py
Doing Linux things.
[Errno 2] No such file or directory: 'file.log'
从输出中,可以看到已 linux_interaction() 运行。 因为 Python 没有遇到异常, 所以它尝试打开 file.log 。该文件不存在, 但没有让程序崩溃, 而是捕获了异常 FileNotFoundError 并向控制台打印一条消息。
finally想象一下,在执行代码后, 总是必须执行某种操作来进行清理。 Python 允许使用以下子句来执行此操作 finally :

看一下下面的示例:
Python
# ...
try:
linux_interaction()
except RuntimeError as error:
print(error)
else:
try:
with open("file.log") as file:
read_data = file.read()
except FileNotFoundError as fnf_error:
print(fnf_error)
finally:
print("Cleaning up, irrespective of any exceptions.")
在此代码中,Python 将执行 finally 子句中的所有内容。 如果在任何 try…except 块中的某个地方遇到异常, 这并不重要。在 macOS 或 Windows 计算机上运行代码将输出以下内容:
Shell
$ python linux_interaction.py
Function can only run on Linux systems.
Cleaning up, irrespective of any exceptions.
finally 请注意,无论是否正在处理异常, 块内的代码都会执行:
Python
# ...
try:
linux_interaction()
finally:
print("Cleaning up, irrespective of any exceptions.")
简化了上面的示例代码, 但 linux_interaction() 仍然在 macOS 或 Windows 系统上引发异常。 如果现在在 Linux 以外的操作系统上运行此代码, 那么将获得以下输出:
$ python linux_interaction.py
Cleaning up, irrespective of any exceptions.
Traceback (most recent call last):
...
RuntimeError: Function can only run on Linux systems.
尽管 Python 引发了 RuntimeError, 该子句中的代码 finally 仍然执行并将消息打印到控制台。
这可能很有帮助,因为如果脚本遇到未处理的异常, 即使是 try…except 块之外的代码也不一定会执行。 在这种情况下,程序将终止, try…except 块之后的代码将永远不会运行。 但是,Python 仍将执行 finally 子句中的代码, 这有助于确保文件句柄和数据库连接等资源得到正确清理。
由于 Python 提供了大量内置异常, 在决定引发哪个异常时可能会找到合适的类型。 然而,有时代码不符合模型。
Python 通过继承内置异常, 可以轻松创建自定义异常类型。 回想一下你的 linux_interaction() 函数:
linux_interaction.py
def linux_interaction():
import sys
if "linux" not in sys.platform:
raise RuntimeError("Function can only run on Linux systems.")
print("Doing Linux things.")
# ...
在这种情况下,使用 aRuntimeError 并不是一个糟糕的选择, 但如果异常名称更具体一些,那就更好了。 为此,可创建自定义异常:
linux_interaction.py
class PlatformException(Exception):
"""Incompatible platform."""
# ...
通常,可通过继承来在 Python 中创建自定义异常 Exception , 它也是大多数内置 Python 异常的基类, 也可以从不同的异常继承,但选择 Exception 通常是最好的选择。
这确实是需要做的全部事情。 在上面的代码片段中, 还添加了一个描述异常类型并用作类主体的文档字符串。
注意: Python 需要在类主体中包含一些缩进代码。 除了使用文档字符串之外, 还可以使用 pass 省略号( ...)。 但是,添加描述性文档字符串可以为自定义异常添加最大价值。
虽然可以自定义异常对象, 但不需要这样做。 通常,为自定义 Python 异常指定一个描述性名称就足够了, 这样就会知道当 Python 在代码中引发此异常时发生了什么。
现在已经定义了自定义异常, 可像任何其他 Python 异常一样引发它:
linux_interaction.py
class PlatformException(Exception):
"""Incompatible platform."""
def linux_interaction():
import sys
if "linux" not in sys.platform:
raise PlatformException("Function can only run on Linux systems.")
print("Doing Linux things.")
# ...
如果现在 linux_interaction() 在 macOS 或 Windows 上调用, 那么将看到 Python 引发自定义异常:
$ python linux_interaction.py
Traceback (most recent call last):
...
PlatformException: Function can only run on Linux systems.
甚至可以使用自定义 PlatformException 作为其他自定义异常的父类, 可以为用户可能运行代码的每个平台进行描述性命名。
至此,已经熟悉了使用 Python 异常的基础知识。 了解语法错误和异常之间的区别后, 了解了在 Python 中引发、捕获和处理异常的各种方法, 以及如何创建自己的自定义异常。
在本文中,可获得使用以下异常相关键字的经验:
raise 允许随时提出异常。assert能够验证是否满足特定条件,如果不满足则引发异常。try子句中,所有语句都会执行,直到遇到异常。except允许捕获并处理 Python 在子句中遇到的一个或多个异常 try 。else允许您编写仅当 Python 在子句中没有遇到异常时才运行的代码段 try 。finally能够执行应始终运行的代码段, 无论 Python 是否遇到任何异常。本文内容来源于网站:https://realpython.com/python-exceptions/, 由小编整理编译。