当一个异常在你的代码中被引发时,Python会打印一个traceback(回溯)。如果你是第一次看到回溯输出,或者你不知道它在告诉你什么,那么它可能会让你不知所措。但是Python回溯具有丰富的信息,可以帮助你诊断和修复代码中引发异常的原因。理解Python回溯提供了什么信息对于成为一个更好的Python程序员至关重要。

在本教程结束时,你将能够:

理解你下一次遇到的回溯识别一些很常见的回溯在处理异常的同时成功记录回溯

什么是Python回溯?

回溯是一个报告,其中包含在你的代码中某个特定点上执行的函数调用。回溯有很多名称,包括堆栈跟踪、堆栈回溯、向后追溯,也许还有其他名称。在Python中,使用的术语是回溯。

当你的程序引发一个异常时,Python将打印当前回溯信息以帮助你知道哪里出错了。下面是一个例子来说明这种情况:

在这里,我们使用参数someone调用greet()。但是,在greet()中,这个变量名没有被使用。相反,它在print()调用中被错误拼写为someon。

注意:本教程假设你理解Python异常。如果你不熟悉或者只是想复习一下,那么你应该查看《Python异常:介绍》。

当你运行这个程序时,你会得到以下回溯:

这里,你已经设置了另一个Python文件,该文件将导入前面的模块greetings.py,并从中使用greet()。下面是运行example.py时会发生的事情:

这将会打印出对所有三个人的问候语。但是,如果你运行这段代码,你会看到一个输出多个回溯的例子:

在上面的例子中,你可能期望a_list是list类型的,它有一个名为.Append()的方法。当你接收到AttributeError异常并看到它是在你尝试调用.append()时引发的,这说明你正在处理的对象类型可能不是你所期望的。

通常,当你期望从一个函数或方法调用返回一个特定类型的对象时,会出现这种情况,你最终会得到一个类型为None的对象。在本例中,错误消息行将写到,AttributeError: 'None类型'对象没有属性'append'。

ImportError

当一个import语句出错时,ImportError会被引发。如果你试图导入的模块找不到,或者你试图从一个模块中导入模块中不存在的内容时,你将得到这个异常,或者它的子类ModuleNotFoundError。Python文档定义了此异常何时被引发:

当import语句在尝试加载模块时遇到困难时引发。当from…import中的“from list”中存在一个无法被找到的名称时也会引发。

下面是一个ImportError 和ModuleNotFoundError被引发的例子。

KeyError的错误消息行会给出找不到的键。这并没有太多的内容,但是,结合回溯的其他内容,但对于修复这个问题来说通常是足够了。

要深入了解KeyError,请查看《Python KeyError异常以及如何处理它们》。

NameError

当你引用了一个代码中未定义的变量、模块、类、函数或其他名称时,将引发一个NameError。Python文档定义了此异常何时被引发:

当本地或全局名称未被找到时引发。

在下面的代码中,greet()接受一个参数person。但在函数本身中,该参数被错误拼写为persn:

SyntaxError的错误消息行只告诉你代码的语法有问题。查看上面的行可以得到问题所在的行,通常用a ^(插入符号)指向问题点。这里,函数的def语句中缺少冒号。

同样,使用SyntaxError回溯,常规的第一行Traceback (most recent call last:也丢失了。这是因为当Python试图解析你的代码时,SyntaxError会被引发,而实际上这些行并没有被执行。

TypeError

当你的代码试图对一个对象执行某些不能执行的操作时,例如试图将一个字符串相加到一个整数中,或者在一个没有定义其长度的对象上调用len(),TypeError就会被引发。Python文档中定义了此异常何时被引发:

当一个操作或函数被应用于一个不合适类型的对象时引发。

下面是TypeError被引发的几个示例:

以上所有引发TypeError的示例都会产生一个包含不同消息的错误消息行。每一条消息都能很好地告诉你哪里出了问题。

前两个示例尝试将字符串和整数相加。然而,它们有细微的不同:

第一个试图将一个str加到一个int。第二个试图将一个int 加到一个 str。

错误消息行反映了这些不同。

最后一个例子尝试在一个int上调用len()。错误消息行告诉你不能对一个int类型执行此操作。

ValueError

当对象的值不正确时,ValueError将被引发。你可以将其视为一个IndexError,当索引值不在序列范围之内时会被引发,只不过ValueError用于更一般的情况。Python文档中定义了此异常何时被引发:

当一个操作或函数接收到一个具有正确类型但值不合适的参数时引发,并且这种情况不能被一个更精确的异常(比如IndexError)描述。

下面是ValueError被引发的两个例子:

在这些例子中,ValueError错误消息行会准确地告诉你这些值存在什么问题:

在第一个示例中,你试图解压缩太多的值。错误消息行甚至告诉你,你期望解压缩3个值,但是只得到了2个值。在第二个例子中,问题是你得到了太多的值,但没有足够的变量来解压缩它们。

如何记录一个回溯?

获得异常及其生成的Python回溯意味着你需要决定如何处理它。通常,修复代码是第一步,但有时问题出在未预期的或不正确的输入上。虽然在代码中提供这些情况很好,但有时通过记录回溯和执行其他操作来隐藏异常也很有意义。

下面是一个更真实的代码示例,它需要让一些Python回溯保持静默。本例使用了requests库。你可以在Python的requests库(指南)中获取更多信息:

这段代码运行得很好。当你运行此脚本时,你将一个URL作为命令行参数提供给它,它将调用该URL,然后打印出HTTP状态码和响应中的内容。甚至在响应是一个HTTP错误状态时,它也可以工作:

但是,有时你的脚本提供的用于检索的URL不存在,或者主机服务器关闭。在这些情况下,这个脚本现在就会引发一个未捕获的ConnectionError异常,并打印一个回溯:

这里的Python回溯可能非常长,还会引发许多其他异常,最终导致ConnectionError被requests库本身引发。如果你向上移动到最后的异常回溯,你就可以看到问题都是从我们的代码urlcall .py中的第5行开始的。

如果你将非法行封装在一个try和except块中,那么捕获适当的异常将允许你的脚本继续处理更多的输入:

上面的代码使用了一个带有try和except块的else子句。如果你不熟悉Python的这一特性,那么请在Python Exceptions:An Introduction中查看else子句。

现在,当你使用一个URL来运行此脚本时,将引发一个ConnectionError,系统会打印一个状态码-1,以及Connection Error的内容:

这运行的很好。然而,在大多数实际系统中,你并不希望只是静默化异常和生成的回溯,而是希望去记录回溯。记录回溯可以让你更好地理解程序中哪些地方出错了。

注意: 要了解更多关于Python日志系统的信息,请查看Python中的logging。

你可以通过导入logging包,获取一个日志记录器并在try和except块的except部分中调用该日志记录器的.exception()来在你的脚本中记录回溯。你的最终脚本应该会类似于以下代码:

现在,当你对一个有问题的URL运行此脚本时,它会打印预期的-1和Connection Error,同时也会记录回溯:

默认情况下,Python将向标准错误(stderr)发送日志消息。看起来我们根本没有抑制回溯输出。但是,如果你在重定向stderr时再次调用它,你可以看到日志系统正在工作,我们可以将日志保存起来,以备以后使用:

结论

Python回溯包含了大量的信息,可以帮助你发现你的Python代码中出现的错误。这些回溯看起来有点吓人,但是一旦你把它分解开来,看看它想向你展示什么,它们就会非常有用。逐行浏览一些回溯将会使你更好地理解它们包含的信息,并帮助你最大限度地利用它们。

在运行代码时获得Python回溯输出是改进代码的一个机会。这是Python试图帮助你的一种方式。

既然你已经了解了如何阅读Python回溯,那么你可以从学习更多有关诊断回溯输出所告诉你的问题的一些工具和技术中获益。Python的内置traceback模块可用于处理和检查回溯。当你需要从回溯输出中获得更多信息时,traceback模块是很有用的。了解更多有关调试Python代码的技术也会很有帮助。

1.《back怎么读 什么是Python回溯? Traceback(回溯)》援引自互联网,旨在传递更多网络信息知识,仅代表作者本人观点,与本网站无关,侵删请联系页脚下方联系方式。

2.《back怎么读 什么是Python回溯? Traceback(回溯)》仅供读者参考,本网站未对该内容进行证实,对其原创性、真实性、完整性、及时性不作任何保证。

3.文章转载时请保留本站内容来源地址,https://www.lu-xu.com/keji/347786.html