在软件开发中,可能会发生不同类型的错误。 它们可能是语法错误,逻辑错误或运行时错误。
语法错误很可能在初始开发阶段发生,并且是由于语法不正确造成的。 编译该程序以执行时,很容易发现语法错误。
另一方面,逻辑错误是逻辑执行不正确的结果。 一个示例是假定未排序列表被排序的程序访问该列表。 逻辑错误是最难跟踪的错误。
如果我们不考虑所有极端情况,则运行时错误是最有趣的错误。 一个示例将尝试访问不存在的文件。
在本教程中,我们将学习如何使用Python处理错误以及如何记录错误,以更好地了解应用程序内部的错误。
在Python中处理异常
让我们从一个简单的程序开始,在Python中添加两个数字。 我们的程序接受两个参数作为输入并打印总和。 这是一个添加两个数字的Python程序:
def addNumbers(a, b):
print a + b
addNumbers(5, 10)
尝试运行上面的Python程序,您应该打印出总和。
15
在编写上述程序时,我们并未真正考虑到任何事情都会出错的事实。 如果传递的参数之一不是数字怎么办?
addNumbers('', 10)
我们尚未处理这种情况,因此我们的程序将崩溃并显示以下错误消息:
Traceback (most recent call last):
File "addNumber.py", line 4, in <module>
addNumbers('', 10)
File "addNumber.py", line 2, in addNumbers
print a + b
TypeError: cannot concatenate 'str' and 'int' objects
我们可以通过检查传递的参数是否为整数来解决上述问题。 但这无法解决问题。 如果代码由于其他原因而崩溃并导致程序崩溃怎么办? 使用遇到错误而崩溃的程序不是一个好主意。 即使遇到未知错误,代码也应足够健壮以优雅地处理崩溃并让用户知道出了点问题。
使用try和except处理异常
在Python中,我们使用try
和except
语句来处理异常。 每当代码崩溃时,都将引发异常而不会导致程序崩溃。 让我们修改加号程序,使其包含try
和except
语句。
def addNumbers(a, b):
try:
return a + b
except Exception as e:
return 'Error occurred : ' + str(e)
print addNumbers('', 10)
Python将在try
和except
语句中处理所有代码。 遇到错误时,控件将传递到except
块,从而跳过两者之间的代码。
如以上代码所示,我们已将代码移至try
和except
语句内。 尝试运行该程序,它应该引发错误消息,而不是使程序崩溃。 异常原因也作为异常消息返回。
上面的方法处理意外的异常。 让我们看一下如何处理预期的异常。 假设我们正在尝试使用Python程序读取特定文件,但是该文件不存在。 在这种情况下,我们将处理异常,并让用户知道该文件发生时不存在。 看一下文件读取代码:
try:
try:
with open('fname') as f:
content = f.readlines()
except IOError as e:
print str(e)
except Exception as e:
print str(e)
在上面的代码中,我们已经处理了IOError
异常处理程序中的文件读取。 如果代码由于文件fname
不可用而中断,则该错误将在IOError
处理程序内处理。 与IOError
异常类似,还有很多标准异常,例如Arithmetic
, OverflowError
和ImportError
,仅举几例。
多个例外
我们可以通过组合如下所示的标准异常来一次处理多个异常:
try:
with open('fname') as f:
content = f.readlines()
printb
except (IOError,NameError) as e:
print str(e)
上面的代码将在执行程序时IOError
和NameError
异常。
finally
条款
假设我们在Python程序中使用了某些资源。 在程序执行期间,它遇到错误,并且只在执行一半时执行。 在这种情况下,将不必要地占用资源。 我们可以使用finally
子句清理此类资源。 看下面的代码:
try:
filePointer = open('fname','r')
try:
content = filePointer.readline()
finally:
filePointer.close()
except IOError as e:
print str(e)
如果在执行上述代码期间,在读取文件时引发了异常, filePointer
在finally
块中关闭filePointer
。
登录Python
当应用程序内部出现问题时,如果我们知道错误的来源,则调试起来会变得更加容易。 引发异常时,我们可以记录所需的信息以跟踪问题。 Python提供了一个简单而强大的日志记录库。 让我们看一下如何在Python中使用日志记录。
import logging
# initialize the log settings
logging.basicConfig(filename='app.log',level=logging.INFO)
try:
logging.info('Trying to open the file')
filePointer = open('appFile','r')
try:
logging.info('Trying to read the file content')
content = filePointer.readline()
finally:
filePointer.close()
except IOError as e:
logging.error('Error occurred ' + str(e))
如上面的代码所示,我们首先需要导入日志记录Python库,然后使用日志文件名和日志记录级别初始化记录器。 有五个日志记录级别:DEBUG,INFO,WARNING,ERROR和CRITICAL。 在这里,我们将日志记录级别设置为INFO,因此将记录INFO及以上日志。
获取堆栈跟踪
在上面的代码中,我们只有一个程序文件,因此更容易找出错误发生的位置。 但是,当涉及多个程序文件时我们该怎么办? 在这种情况下,获取错误的堆栈跟踪信息有助于查找错误的来源。 可以记录异常的堆栈跟踪,如下所示:
import logging
# initialize the log settings
logging.basicConfig(filename = 'app.log', level = logging.INFO)
try:
filePointer = open('appFile','r')
try:
content = filePointer.readline()
finally:
filePointer.close()
except IOError as e:
logging.exception(str(e))
如果尝试运行上述程序,则在引发异常时,将在日志文件中记录以下错误:
ERROR:root:[Errno 2] No such file or directory: 'appFile'
Traceback (most recent call last):
File "readFile.py", line 7, in <module>
filePointer = open('appFile','r')
IOError: [Errno 2] No such file or directory: 'appFile'
包起来
在本教程中,我们看到了如何开始使用Python处理错误以及如何使用日志记录模块记录错误。 我们看到了try
, except
和finally
语句的用法,这在处理Python中的错误处理时非常有用。 有关更多详细信息,建议您阅读有关Logging的官方文档 。 还可以查看有关在Python中处理异常的文档 。
请在下面的评论中告诉我们您的想法。
翻译自: https://code.tutsplus.com/tutorials/error-handling-logging-in-python--cms-27932