Python错误处理

使用回溯查找错误

Python 中的异常是语言的核心功能。 你可能会惊讶地发现,错误的源头高亮显示为某个功能。 让你惊讶的原因是,可靠的软件工具似乎不会崩溃并产生回溯(多行文本,这些文本指示错误如何开始和结束)。

但异常非常有用,因为异常可以生成描述性错误消息以帮助决策。 它们有助于处理预期和意外的问题。

回溯

回溯是文本的正文,可指向未处理错误的来源(和终点)。 通过了解回溯的组成,你可以更高效地修复错误或调试不能正常工作的程序。

当你首次在 Python 中遇到异常时,可能会尝试通过取消显示来避免此错误。 当程序发生的错误未经处理时,回溯将显示为输出。 正如你在本模块中看到的那样,回溯非常有用。 有几种方法可以正确处理错误,使这些错误不会显示或仅显示有用信息。

打开 Python 交互式会话并尝试打开不存在的文件:

python 复制代码
open("/path/to/mars.jpg")
python 复制代码
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
FileNotFoundError: [Errno 2] No such file or directory: '/path/to/mars.jpg'

该输出具有几个关键部分。 首先,回溯提到输出的顺序。 然后,它会报告该文件为 stdin(交互式终端中的输入),位于输入的第一行。 错误为 FileNotFoundError(异常名称)异常,这意味着该文件不存在,或者可能不存在该文件的目录。

这里提供了大量信息。 很难理解为什么第 1 行是有意义的,或者 Errno 2 是什么意思。

在 Visual Studio Code 中打开所需的目录,并创建名为 open.py 的 Python 文件。

python 复制代码
def main():
    open("/path/to/mars.jpg")

if __name__ == '__main__':
    main()
python 复制代码
python3 open.py
python 复制代码
Traceback (most recent call last):
  File "/tmp/open.py", line 5, in <module>
    main()
  File "/tmp/open.py", line 2, in main
    open("/path/to/mars.jpg")
FileNotFoundError: [Errno 2] No such file or directory: '/path/to/mars.jpg'

错误输出现在就比较有意义了。 路径指向名为 open.py 的单个文件。 输出提到错误在第 5 行开始,其中包括对 main() 的调用。 接下来,输出跟踪错误至 open() 函数调用中的第2行。 最后,FileNotFoundError 再次报告文件或目录不存在。

回溯几乎始终包含以下信息:

涉及对每个函数的每次调用的所有文件路径。

与每个文件路径关联的行号。

产生异常时涉及的函数、方法或类的名称。

引发的异常的名称。

处理异常

当你第一次发现显示大回溯作为输出的异常时,你可能会尝试捕获每个错误以防止发生这种情况。

如果你的任务是到达火星,导航系统上的文本显示"发生错误"时,该怎么办? 假设没有任何其他信息或上下文,只有闪烁的红灯和错误文本。 作为一名开发人员,站在程序的另一方角度看问题会很有用:当出错时,用户可以做什么?

虽然此模块介绍了如何通过捕获异常来处理异常,但并不需要始终捕获异常。 有时允许引发异常会很有用,其他调用方可以处理错误。

try和except块

让我们使用导航器示例来创建代码,以便为火星任务打开配置文件。 配置文件可能会遇到各种问题,因此在问题出现时准确报告问题非常重要。 我们知道,如果文件或目录不存在,则会引发 FileNotFoundError。 如果我们想要处理此异常,可以使用 try 和 except 块:

python 复制代码
try:
     open('config.txt')
except FileNotFoundError:
     print("Couldn't find the config.txt file!")

Output

Couldn't find the config.txt file!

在 try 关键字之后,添加可能引发异常的代码。 接下来,添加 except 关键字与可能的异常,后跟在该条件发生时需要运行的任何代码。 由于 config.txt 在系统中不存在,因此 Python 将打印配置文件不存在。 try 和 except 块以及有用的消息会阻止回溯,并仍通知用户有关此问题的信息。

虽然文件不存在很常见,但它并不是你可能发现的唯一错误。 无效的文件权限会阻止读取文件,即使文件存在也是如此。 让我们在 Visual Studio Code 中创建一个名为 config.py 的新 Python 文件。 将用于查找和读取导航系统配置文件的以下代码添加到该文件:

python 复制代码
def main():
    try:
        configuration = open('config.txt')
    except FileNotFoundError:
        print("Couldn't find the config.txt file!")


if __name__ == '__main__':
    main()

接下来,创建一个名为 config.txt 的目录。 尝试调用 config.py 文件以查看新错误,该错误应如下所示:

python3 config.py
Output

Traceback (most recent call last):

File "/tmp/config.py", line 9, in <module>

main()

File "/tmp/config.py", line 3, in main

configuration = open('config.txt')

IsADirectoryError: [Errno 21] Is a directory: 'config.txt'

处理此错误的一种无用方法是捕获所有可能的异常,以防出现回溯。 若要了解捕获所有异常不可行的原因,请通过在新创建的 config.py 文件中更新 main() 函数来尝试:

python 复制代码
def main():
    try:
        configuration = open('config.txt')
    except Exception:
        print("Couldn't find the config.txt file!")

现在,在具有不正确权限的 config.txt 目录所在的同一位置再次运行该代码:

python3 config.py
Couldn't find the config.txt file!

现在的问题是错误消息不正确。 此目录的确存在,但它具有不同的权限,并且 Python 无法读取。 处理软件错误时,遇到以下错误可能会让人沮丧:

错误不指出真正的问题。

错误给出与实际问题不匹配的输出。

错误不提示可以执行哪些操作来解决问题。

让我们修复这段代码,以解决所有这些问题。 恢复为捕获 FileNotFoundError,然后添加另一个 except 块以捕获 PermissionError:

python 复制代码
def main():
    try:
        configuration = open('config.txt')
    except FileNotFoundError:
        print("Couldn't find the config.txt file!")
    except IsADirectoryError:
        print("Found config.txt but it is a directory, couldn't read it")

现在在 config.txt 目录所在的位置再次运行它:

python3 config.py
Found config.txt but couldn't read it

现在删除 config.txt 目录,以确保改为访问第一个 except 块:

rm -f config.txt

python3 config.py
Couldn't find the config.txt file!

如果错误具有类似的性质,并且无需单独处理,则可以通过在 except 行中使用括号将异常归为一组。 例如,如果导航系统负载过大,并且文件系统变得太忙,则很有必要同时捕获 BlockingIOError 和 TimeOutError:

python 复制代码
def main():
    try:
        configuration = open('config.txt')
    except FileNotFoundError:
        print("Couldn't find the config.txt file!")
    except IsADirectoryError:
        print("Found config.txt but it is a directory, couldn't read it")
    except (BlockingIOError, TimeoutError):
        print("Filesystem under heavy load, can't complete reading configuration file")

即使可以将异常归为一组,也只有在不需要单独处理异常时才这样做。 避免将多个异常归为一组以提供普通的错误消息。

如果需要访问与异常相关的错误,则必须更新 except 行以包含 as 关键字。 如果异常太过普通,则这种方法就非常方便并且错误消息会很有用:

python 复制代码
try:
    open("mars.jpg")
except FileNotFoundError as err:
     print("Got a problem trying to read the file:", err)

在本例中,as err 意味着 err 成为一个变量,而异常对象则作为值。 然后,它使用此值来打印与异常相关的错误消息。 使用此方法的另一个原因是直接访问该错误的属性。 例如,如果捕获到更加普通的 OSError 异常,该异常是 FilenotFoundError 和 PermissionError 的父异常,则可以通过 .errno 属性来区分它们:

python 复制代码
try:
    open("config.txt")
except OSError as err:
     if err.errno == 2:
         print("Couldn't find the config.txt file!")
     elif err.errno == 13:
        print("Found config.txt but couldn't read it")
相关推荐
凌盛羽1 小时前
C#对Excel表csv文件的读写操作
开发语言·windows·物联网·microsoft·c#·excel
途途途途1 小时前
Python 给 Excel 写入数据的四种方法
windows·python·excel
VBA63371 小时前
VBA高级应用30例应用在Excel中的ListObject对象:向表中添加注释
开发语言
Dontla1 小时前
Rust字节数组(Byte Array)Rust u8、Vec<u8>、数组切片、向量切片、字符串转字节数组转字符串、&[u8]类型:字节数组引用
开发语言·rust
数据小爬虫@3 小时前
Python爬虫:如何优雅地“偷窥”商品详情
开发语言·爬虫·python
CV大法好3 小时前
刘铁猛p3 C# 控制台程序引用System.Windows.Forms报错,无法引用程序集 解决方法
开发语言·c#
闰土_RUNTU3 小时前
Pytorch分布式训练print()使用技巧
人工智能·pytorch·python·分布式训练·训练技巧
Days20503 小时前
uniapp小程序增加加载功能
开发语言·前端·javascript
零光速3 小时前
数据处理与统计分析——10-Pandas可视化-Matplotlib的常用API
数据结构·python·数据分析·pandas·matplotlib