Python 中的 Traceback2024年8月29日 | 13分钟阅读 Python Traceback 简介当 Python 代码中引发异常时,Python 会返回一个 Traceback。初次看到或不了解其含义时,**Traceback** 的输出可能令人费解。然而,Python 编程语言中的 Traceback 包含了大量数据,可以帮助我们诊断和修复代码中引发异常的原因。理解 Python traceback 提供的数据对于成为一名更好的 Python 程序员至关重要。 在下面的教程中,我们将讨论 Python 编程语言中的 Traceback。但在教程结束时,我们将能够识别一些最常见的 traceback。 那么,让我们开始吧。 理解 Python 编程语言中的 Traceback**Traceback** 是一个报告,其中包含在特定时间点代码行上对函数的调用。Traceback 有多种名称,例如 **stack trace、stack traceback、backtrace** 等等。然而,在 Python 编程语言中,我们使用“Traceback”一词。 每当程序引发异常时,Python 都会返回当前的 Traceback,以帮助我们了解出了什么问题。让我们看下面的示例来说明一种这种情况。 示例 输出 Traceback (most recent call last): File "D:\Python\pytrace.py", line 10, in 说明 在上面的代码片段中,我们定义了一个名为 **welcome** 的自定义函数,该函数接受一个名为 **“name”** 的参数。但是,在函数内打印一些消息时,我们将 **“name”** 参数拼写错误为 **“nam”**。结果,在调用函数时引发异常时,Python 打印了一个 traceback 消息。 正如我们在输出中观察到的,traceback 消息包含了诊断问题所需的所有信息。traceback 消息的最后一行表示引发的异常类型,以及与该异常相关的适当数据。traceback 消息的早期行指示了导致异常的代码。 在上面的 traceback 中,异常是 **NameError**,这意味着引用了未定义的名称(例如变量、类、函数)。在本例中,引用的名称是 **“nam”**。 在这种情况下,最后一行包含足够的信息来帮助我们解决问题。搜索代码中拼写错误的名称 **nam**,它将正确地指向我们。通常,代码会复杂得多。 阅读 Python 中的 TracebackPython 中的 Traceback 包含大量关于代码行中引发的异常的宝贵数据。在下一节中,我们将了解如何阅读不同的 traceback 以了解 traceback 中存储的各种数据。 Python traceback 分为不同的部分。每个部分都有其重要性。让我们看下面的 traceback Traceback 在 Python 编程语言中,从下往上阅读 traceback 消息是一个好习惯。现在,让我们详细了解上面的 traceback。
当在命令行和 REPL 中执行代码时,traceback 的输出会有些不同。让我们以在 REPL 中执行相同的示例并理解 traceback 输出。 REPL 正如我们在上面的 REPL 代码片段中观察到的,traceback 消息在文件名处返回“** 注意:如果有些人喜欢查看不同编程语言中的堆栈跟踪,那么与 Python 编程语言中的 traceback 相比,它的外观会有很大的不同。大多数语言将异常显示在顶部,然后从上到下(最近的调用到最远的调用)。而在 Python 中,traceback 应从下往上阅读。这非常有用,因为当返回 traceback 时,终端通常会停在输出的底部,为我们提供了开始阅读 traceback 的理想位置。 理解 Python 中的一些常见 Traceback一旦我们理解了在引发异常时如何在 Python 中阅读 Traceback,让我们来了解一些在编码时可能看到的常见 traceback。 以下是一些我们可能遇到的标准异常,以及它们的含义、引发原因以及我们可以在其 traceback 中找到的数据。 AttributeError当尝试访问对象上不存在该已定义属性的属性时,会引发 **AttributeError** 异常。Python 文档描述了何时会引发 **AttributeError** 异常。 当属性的引用或赋值失败时,将引发此异常。 让我们看下面的示例,其中引发了 **AttributeError** 异常。 示例 输出 Traceback (most recent call last): File "D:\Python\pytrace.py", line 2, in 说明 在上面的代码片段中,我们定义了一个整数并尝试访问其属性。但是,当我们执行程序时,它引发了 **AttributeError** 异常,并指出特定的对象类型,在本例中为 **int**,没有访问的属性,即 **an_attribute**。查看错误消息行中的 **AttributeError** 异常可以方便地帮助我们识别我们试图访问的属性以及如何修复它。 通常,每当引发此类异常时,它都表示我们可能正在处理一个实例,而该实例不是我们想要的类型。 让我们看另一个示例以更好地说明 示例 输出 Traceback (most recent call last): File "D:\Python\pytrace.py", line 5, in 说明 在上面的代码片段中,我们定义了一个列表,并使用 **append()** 方法添加另一个元素到列表中。但是,结果是,我们可能期望 **my_list** 是 **list** 类型,它包含一个名为 **append()** 的方法。当我们收到 **AttributeError** 异常时,我们观察到它是在调用 **append()** 函数时引发的,这表明我们可能没有处理我们想要的那个对象类型。 通常,这发生在当我们期望从方法或函数调用返回的对象是特定类型时,但最终我们得到了 None 类型对象。在上述情况下,错误消息行将显示 **AttributeError: 'NoneType' object has no attribute 'append'**。 ImportError当 **import** 语句出现问题时,会引发 **ImportError** 异常。如果找不到我们试图导入的模块或库,或者从库或模块中导入的内容不存在,我们将收到此异常,或其子类 **ModuleNotFoundError**。Python 文档指出了何时会引发 **ImportError** 异常。 当 **import** 语句难以加载库或模块时,将引发此异常。此外,当 **from ... import** 中的 **'from list'** 包含一个找不到的名称时,也会引发此异常。 让我们看一个演示如何引发 **ImportError** 和 **ModuleNotFoundError** 的示例。 示例 输出 # Output for the first line Traceback (most recent call last): File "D:\Python\pytrace.py", line 2, in 说明 在上面的代码片段中,我们试图导入一个不存在的库或模块 **xyz**,这导致了 **ModuleNotFoundError** 异常。另一方面,当我们尝试从存在的 collections 库导入不存在的模块 **xyz** 时,程序引发了 **ImportError** 异常。traceback 底部的错误消息行显示了哪个特定项无法导入,在这两种情况下,都是 **xyz**。 IndexError当尝试从序列(如元组或列表)中检索索引,但在序列中找不到该索引时,通常会引发 **IndexError** 异常。Python 文档指出了何时会引发 Index 异常。 当序列的下标越界时,将引发此异常。 让我们看下面的示例,演示如何引发 **IndexError** 异常。 示例 输出 Traceback (most recent call last): File "D:\Python\pytrace.py", line 5, in 说明 在上面的代码片段中,我们定义了一个包含四个元素的列表 **my_list**。但是,当我们试图打印索引号为 **5** 的元素时,程序引发了 **IndexError** 异常。**IndexError** 异常的错误消息没有提供充分的信息。我们可以观察到我们有一个序列引用,即 **out of range**,以及序列的类型,在这种情况下是列表。结合 traceback 的其余部分,这些数据通常足以帮助我们快速识别如何解决问题。 KeyError**KeyError** 异常与 **IndexError** 异常类似,当尝试访问映射(通常在字典等数据结构中)中不存在的键时会引发此异常。Python 文档指出了何时会引发 **KeyError** 异常。 当字典(映射)键在现有键集中找不到时,将引发此异常。 让我们看下面的示例来理解如何引发 **KeyError** 异常。 示例 输出 Traceback (most recent call last): File "D:\Python\pytrace.py", line 5, in 说明 在上面的代码片段中,我们定义了一个包含一些键值对的 **dictionary**。然后我们试图访问字典中不存在的 **key** 的 **value**。结果,程序引发了 **KeyError** 异常,并指出我们正在寻找的 **key** 无法找到。 NameError当我们在代码行中引用了未定义的变量、类、函数、模块或其他名称时,会引发 **NameError** 异常。Python 文档指出了何时会引发 **NameError** 异常。 当找不到局部或全局名称时,将引发此异常。 让我们看下面的示例以理解如何引发 **NameError** 异常。 示例 输出 Traceback (most recent call last): File "D:\Python\pytrace.py", line 6, in 说明 在上面的示例中,我们定义了一个名为 **myself()** 的函数,它接受一个名为 **name** 的参数。但是,我们在打印一些语句时将名称拼写错误为 **nam**。然后我们调用了该函数。结果,程序引发了 **NameError** 异常,因为名称 **'nam'** 在程序中未定义。 SyntaxError当 Python 程序的语法不正确时,通常会引发 **SyntaxError** 异常。Python 文档指出了何时会引发 **SyntaxError** 异常。 当解析器遇到 Python 语法错误时,将引发此异常。 让我们看一个说明如何引发 **SyntaxError** 异常的示例。 示例 输出 File "D:\Python\pytrace.py", line 2 def myself( name ) ^ SyntaxError: invalid syntax 说明 在上面的语法中,我们定义了一个名为 **myself()** 的函数,但忘记在函数定义后包含冒号“**:**”。结果,当我们执行该函数时,程序引发了 **SyntaxError** 异常,并指出了程序语法的问题。代码行下方的 ^(插入符号)标记表示问题的位置。 此外,我们可以观察到 **SyntaxError** traceback 消息不显示常规的第一行“**Traceback (most recent call last):**”。这是因为 **SyntaxError** 异常是在 Python 尝试分析代码行时引发的,并且代码行不是以字面方式处理的。 TypeError当语法尝试对无法执行该函数的实例执行某些函数时,会引发 **TypeError** 异常,例如尝试将整数添加到字符串,或者对未指定长度的对象调用 **len()** 函数。Python 文档指出了何时会引发 **TypeError** 异常。 当函数或操作应用于错误类型的对象时,将引发此异常。 让我们看下面的示例,演示如何引发 **TypeError** 异常。 示例 输出 Traceback (most recent call last): File "D:\Python\pytrace.py", line 4, in 说明 在上面的示例中,我们定义了两个变量,一个为 **整数**,一个为 **字符串**。然后我们对这些变量执行加法运算并尝试打印结果。但是,程序返回了 **TypeError** 异常,因为我们试图将 **整数** 值与 **字符串** 值相加。 同样,当我们在 **'int'** 数据类型上使用 **len()** 函数时,也会引发此异常。 让我们看下面的示例来演示这一点。 示例 输出 Traceback (most recent call last): File "D:\Python\pytrace.py", line 5, in 说明 在上面的示例中,我们定义了一个 **'int'** 数据类型的变量,并尝试对该变量执行 **len()** 函数。但是,程序引发了 **TypeError**,并指出我们不能对 **'int'** 数据类型的对象执行 **len()** 函数。 ValueError当对象的值不正确时,会引发 **ValueError** 异常。此异常与 **IndexError** 异常类似,因为在 **IndexError** 异常的情况下,索引值超出了序列的范围。相比之下,**ValueError** 异常适用于更通用的场景。Python 文档指出了何时会引发 **ValueError** 异常。 当函数或操作接收到类型正确的参数;但是,值不合适且状态没有由 **IndexError** 等更具体的异常定义时,将引发此异常。 让我们看一个基于 **ValueError** 异常的示例。 示例 输出 Traceback (most recent call last): File "D:\Python\pytrace.py", line 2, in 说明 在上面的示例中,我们试图解包四个值,但只得到了三个。因此,程序引发了 **ValueError** 异常。 让我们看另一个基于 **ValueError** 异常的示例。 示例 输出 Traceback (most recent call last): File "D:\Python\pytrace.py", line 2, in 说明 在上面的语法中,我们试图解包太多的值。结果,程序返回了 **ValueError** 异常,并指出没有足够的值可以解包(预期 4 个,得到 3 个)。 |
我们请求您订阅我们的新闻通讯以获取最新更新。