7错误和异常处理

文章介绍了Python中的程序错误类型,包括语法错误、运行时错误和逻辑错误,并详细讲解了异常处理机制,如try-except、自定义异常类和内置异常类。此外,还讨论了断言处理以及使用logging模块进行日志记录的方法,帮助开发者更好地调试和维护Python程序。
摘要由CSDN通过智能技术生成

7.1 程序的错误

​ 程序的编写和运行不可避免产生错误(bugs)和异常(exceptions),Python语言采用结构化的异常处理机制捕获和处理异常.

7.1.1 语法错误

# | 错误类型 | 描述 | 示例 |
# | --- | --- | --- |
# | SyntaxError | Python语法错误 | print("Hello, World!" |
# | IndentationError | 缩进错误 | def foo():\nprint("Hello, World!") |
# | NameError | 未定义变量错误 | print(x) |
# | TypeError | 类型错误 | "5" + 6 |
# | IndexError | 索引错误 | x = [1, 2, 3]\nprint(x[3]) |
# | KeyError | 字典键错误 | x = {'a': 1, 'b': 2}\nprint(x['c']) |
# | AttributeError | 属性错误 | x = 1\nx.append(2) |
# | ValueError | 值错误 | int("abc") |

以上三线表介绍了Python中常见的语法错误类型、错误描述和示例代码。其中,SyntaxError是指Python语法错误,例如缺少括号、缺少冒号等;IndentationError是指缩进错误,例如在代码块中缺少缩进或者不一致的缩进;NameError是指未定义变量错误,例如使用未定义的变量或者函数;TypeError是指类型错误,例如将字符串和整数进行相加;IndexError是指索引错误,例如访问一个不存在的列表元素;KeyError是指字典键错误,例如访问一个不存在的字典键;AttributeError是指属性错误,例如尝试在一个非对象数据类型上调用对象方法;ValueError是指值错误,例如将一个无法转换为整数的字符串传递给int()函数。

在编写Python代码时,了解这些常见的错误类型可以帮助我们更快地定位和解决错误。同时,Python也提供了丰富的调试工具,例如pdb和print语句,可以帮助我们进一步定位和解决其他类型的错误。

7.1.2 运行时错误

解释执行过程中产生的错误

# | 错误类型 | 描述 | 示例 |
# | --- | --- | --- |
# | ZeroDivisionError | 除以零错误 | 1 / 0 |
# | FileNotFoundError | 文件不存在错误 | f = open("file.txt", "r") |
# | TypeError | 类型错误 | "5" + 6 |
# | ValueError | 值错误 | int("abc") |
# | NameError | 未定义变量错误 | print(x) |
# | IndexError | 索引错误 | x = [1, 2, 3]\nprint(x[3]) |
# | KeyError | 字典键错误 | x = {'a': 1, 'b': 2}\nprint(x['c']) |
# | AttributeError | 属性错误 | x = 1\nx.append(2) |

7.1.3 逻辑错误

程序可以执行(程序本身运行不报错),但执行结果不正确.

7.2 异常处理

7.2.1 异常处理概述

Python中的异常处理是一种机制,用于在程序运行时检测和处理错误。当Python程序发生错误时,通常会抛出一个异常对象,该对象包含有关错误的信息。我们可以使用try-except语句来捕获和处理异常,以便程序可以在出现错误时继续运行,而不是立即停止。

try-except语句的基本语法如下:

try:
    # 可能会出现异常的代码块
except ExceptionType:
    # 处理该异常的代码块

在try代码块中,我们可以放置可能会出现异常的代码,例如读取文件、网络请求、数据库查询等。如果try代码块中的代码发生异常,则会抛出一个异常对象,我们可以使用except语句来捕获该异常并处理它。在except语句中,我们可以编写处理异常的代码,例如打印错误信息、记录错误日志、给用户友好的提示等。

如果try代码块中发生多个可能的异常,我们可以使用多个except语句来处理不同类型的异常。例如:

try:
    # 可能会出现异常的代码块
except TypeError:
    # 处理类型错误的代码块
except ValueError:
    # 处理值错误的代码块
except Exception as e:
    # 处理其他异常的代码块,将异常对象保存到变量e中

在上面的代码中,如果try代码块中发生类型错误,则会执行第一个except语句中的代码;如果发生值错误,则会执行第二个except语句中的代码;如果发生其他类型的异常,则会执行第三个except语句中的代码,并将异常对象保存到变量e中。

除了使用except语句来处理异常外,我们还可以使用finally语句来编写一些无论是否发生异常都需要执行的代码,例如关闭文件、释放资源等。finally语句的基本语法如下:

try:
    # 可能会出现异常的代码块
except ExceptionType:
    # 处理该异常的代码块
finally:
    # 无论是否发生异常,都会执行的代码块

在上面的代码中,无论try代码块是否发生异常,都会执行finally语句中的代码。

总之,异常处理是Python编程中非常重要的一部分,它可以帮助我们编写更健壮和可靠的程序,避免程序因为错误而崩溃或出现不可预期的行为。

7.2.2 内置的异常类

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gyrpwoZn-1686328056581)(C:\Users\29363\Desktop\笔记\python\img\exception.png)]

7.2.3 raise引发异常

在Python中,raise语句用于手动引发异常。通常情况下,Python会自动引发异常,例如在发生除以零错误或尝试访问不存在的字典键时。但是,有时我们需要在程序中手动引发异常,以便在特定情况下停止程序的执行或引发自定义异常。

raise语句的基本语法如下:

raise ExceptionType("Error message")

在上面的代码中,ExceptionType是一个异常类,可以是Python内置的异常类或自定义的异常类,"Error message"是一个字符串,用于描述异常的详细信息。当程序执行到raise语句时,会引发一个指定类型的异常,并将错误信息传递给该异常对象。

例如,以下是一个自定义的异常类,用于在数字小于零时引发ValueError异常:

class NegativeNumberError(ValueError):
    pass
    
def check_positive_number(num):
    if num < 0:
        raise NegativeNumberError("Number must be positive")
    else:
        print("Number is positive")

在上面的代码中,当调用check_positive_number函数并传递一个小于零的数字时,会引发NegativeNumberError异常,并打印出错误信息"Number must be positive"。

总之,raise语句是Python中一个非常有用的工具,它允许我们手动引发异常,并在程序中处理和记录特定类型的错误。但是,在使用raise语句时,我们应该谨慎地选择异常类型和错误信息,以便在程序出现异常时能够提供有用的信息。

7.2.4 捕获处理异常机制概述

​ 程序某个方法抛出异常后,Python虚拟机通过调用堆栈查找相应的异常捕获程序.如果找到匹配的异常捕获程序(即调用堆栈中的某函数使用try…except语句捕获异常),则执行相应的处理程序(try…except语句中匹配的except语句块).如果堆栈中没有匹配的异常捕获程序,则Python虚拟级捕获处理异常

7.2.5 自定义异常类

在Python中,我们可以自定义异常类来描述程序中特定的错误或异常。自定义异常类继承自Python内置的Exception类或其他异常类,可以定义自己的错误信息和异常处理方式,以便更好地捕获和处理程序中的错误。

自定义异常类的基本语法如下:

class CustomException(Exception):
    def __init__(self, message):
        self.message = message

在上面的代码中,我们定义了一个名为CustomException的自定义异常类,它继承自Python内置的Exception类。在CustomException类的构造函数中,我们可以定义自己的错误信息,以便在程序中引发异常时提供有用的信息。

以下是一个简单的例子,演示如何定义和使用自定义异常类:

class NegativeNumberError(Exception):
    def __init__(self, message):
        self.message = message

def check_positive_number(num):
    if num < 0:
        raise NegativeNumberError("Number must be positive")
    else:
        print("Number is positive")

try:
    check_positive_number(-1)
except NegativeNumberError as e:
    print(e.message)

在上面的代码中,我们定义了一个名为NegativeNumberError的自定义异常类,用于在数字小于零时引发异常。当调用check_positive_number函数并传递一个小于零的数字时,会引发NegativeNumberError异常,并打印出错误信息"Number must be positive"。

总之,自定义异常类是Python中一个非常有用的工具,它允许我们更好地描述程序中特定的错误或异常,并提供有用的错误信息和异常处理方式。在编写Python代码时,我们应该考虑使用自定义异常类来提高程序的可读性和可维护性。

class NumberError(Exception):  #自定义异常类,继承于Exception
    def __init__(self,data):
        Exception.__init__(self, data)
        self.data = data
    def __str__(self):        #重载__str__方法
        return self.data + ': 非法数值(< 0)'
def total(data):
    total = 0
    for i in data:
        if i < 0: raise NumberError(str(i))
        total += i
    return total
#测试代码
data1 = (44, 78, 90, 80, 55)
print('总计=', total(data1))
data2 = (44, 78, 90, -80, 55)
print('总计=', total(data2))

在这里插入图片描述

7.3 断言处理

7.3.1 断言处理概述

在Python中,断言(assertion)是一种用于调试和测试程序的工具,它用于检查代码中的某个条件是否为真,如果为假,则会引发AssertionError异常。通常,我们使用断言来检查程序中的一些前置条件或不变量,以确保程序的正确性。

断言的基本语法如下:

assert expression, message

在上面的代码中,expression是一个布尔表达式,用于检查某个条件是否为真;message是一个可选的字符串,用于描述断言失败时的错误信息。

当Python执行到assert语句时,它会首先计算expression的值,如果为True,则程序会继续执行;如果为False,则会引发AssertionError异常,并将message作为异常的错误信息。

以下是一个简单的例子,演示如何使用断言来检查程序中的前置条件:

def divide(a, b):
    assert b != 0, "Cannot divide by zero"
    return a / b

print(divide(10, 2))
print(divide(10, 0))

在上面的代码中,我们定义了一个名为divide的函数,用于计算两个数的商。在函数中,我们使用assert语句来检查除数是否为零。当调用divide函数并传递一个除数为零的参数时,会引发AssertionError异常,并打印出错误信息"Cannot divide by zero"。

总之,断言是Python中一个非常有用的工具,它可以帮助我们检查程序中的前置条件或不变量,以提高程序的正确性和可读性。但是,在使用断言时,我们应该谨慎选择断言的条件和错误信息,以便在程序出现问题时能够提供有用的信息。通常情况下,断言应该仅用于调试和测试阶段,而不应该在生产环境中使用。

7.4 程序的基本调试方法

在Python中,我们可以使用以下基本调试方法来诊断和解决程序中的问题:

  1. 打印调试信息:在程序中添加print语句来输出变量值、调用堆栈等信息,以便诊断程序中的问题。这是最基本、最常见的调试方法,但也是最不方便和最不可靠的方法之一。

  2. 使用pdb调试器:Python自带了一个pdb调试器,它可以帮助我们在程序执行期间暂停程序的执行,查看变量值、调用堆栈等信息,以便诊断和解决程序中的问题。可以在程序中添加pdb.set_trace()语句来启动pdb调试器。

  3. 使用IDE的调试功能:许多Python集成开发环境(IDE)都提供了调试功能,例如PyCharm、VS Code等。可以使用IDE的调试功能来逐步执行程序、查看变量值、设置断点等,以便更方便地诊断和解决程序中的问题。

  4. 使用第三方调试器:除了Python自带的pdb调试器之外,还有许多第三方调试器可供选择,例如Winpdb、PyDev等。这些调试器提供了更高级的功能,例如多线程调试、远程调试等,可以帮助我们更方便地诊断和解决程序中的问题。

总之,调试是Python程序开发中不可避免的一部分,我们应该熟练掌握基本的调试方法,并根据需要选择适当的工具和技术,以提高程序的质量和可维护性。

7.5 使用logging模块记录日志

7.5.1 logging模块概述

在Python中,logging模块是一个用于记录程序运行状态和错误信息的标准库。通过使用logging模块,我们可以将程序的输出写入到文件、终端、网络等不同的位置,并按照不同的等级(如DEBUG、INFO、WARNING、ERROR、CRITICAL)来分类和过滤输出信息,以便更好地诊断和解决程序中的问题。

Python的logging模块由以下几个组成部分组成:

  1. 日志器(Logger):用于创建和管理日志记录器对象。每个Logger对象都有一个名称,用于标识该记录器对象。

  2. 处理器(Handler):用于将日志记录器对象的输出发送到不同的目标,如终端、文件、网络等。

  3. 格式器(Formatter):用于指定日志记录的格式,如时间、等级、消息等。

  4. 过滤器(Filter):用于过滤某些不需要记录的日志记录。

下面是每个组成部分的具体功能:

  1. 日志器(Logger):Logger对象用于创建和管理日志记录器,可以通过Logger对象来控制日志记录的等级、输出位置、格式等。Logger对象可以通过名称进行分层管理,以便更好地组织和管理日志记录。

  2. 处理器(Handler):Handler对象用于将日志记录器对象的输出发送到不同的目标,如终端、文件、网络等。可以使用不同类型的处理器来将日志记录输出到不同的位置,例如StreamHandler用于将日志记录输出到终端,FileHandler用于将日志记录输出到文件。

  3. 格式器(Formatter):Formatter对象用于指定日志记录的格式,可以包含时间、等级、消息等信息。可以使用不同的格式器来控制日志记录的输出格式,以便更好地组织和管理日志记录。

  4. 过滤器(Filter):Filter对象用于过滤某些不需要记录的日志记录,可以控制哪些日志记录需要输出,哪些不需要输出。可以使用不同的过滤器来过滤不同类型的日志记录,以便更好地组织和管理日志记录。

总之,logging模块的各组成部分共同协作,来实现对程序的运行状态和错误信息进行记录和管理的功能,以便更好地诊断和解决程序中的问题。在编写Python代码时,我们应该熟悉logging模块的各组成部分的功能和用法,以便更好地使用它来提高程序的可读性和可维护性。

7.5.2 logging的配置和使用

logging模块的基本用法如下:

  1. 导入logging模块:
import logging
  1. 设置日志等级和格式:
logging.basicConfig(level=logging.DEBUG, format='%(asctime)s - %(levelname)s - %(message)s')

在上面的代码中,我们使用basicConfig()函数来设置日志等级和格式。level参数用于指定最低的日志等级,只有等级大于等于该等级的日志才会被输出;format参数用于指定日志记录的格式,可以包含时间、等级、消息等信息。

  1. 记录日志:
logging.debug('This is a debug message')
logging.info('This is an info message')
logging.warning('This is a warning message')
logging.error('This is an error message')
logging.critical('This is a critical message')

在上面的代码中,我们使用debug()、info()、warning()、error()和critical()函数来分别记录不同等级的日志。

  1. 输出日志:
logging.basicConfig(filename='example.log', level=logging.DEBUG, format='%(asctime)s - %(levelname)s - %(message)s')

在上面的代码中,我们使用filename参数来指定日志输出到的文件名。可以将filename设置为None,以便将日志输出到终端或其他位置。

e’)


在上面的代码中,我们使用debug()、info()、warning()、error()和critical()函数来分别记录不同等级的日志。

4. 输出日志:

```python
logging.basicConfig(filename='example.log', level=logging.DEBUG, format='%(asctime)s - %(levelname)s - %(message)s')

在上面的代码中,我们使用filename参数来指定日志输出到的文件名。可以将filename设置为None,以便将日志输出到终端或其他位置。

总之,logging模块是Python中一个非常有用的工具,它可以帮助我们记录程序的运行状态和错误信息,以便更好地诊断和解决程序中的问题。在编写Python代码时,我们应该考虑使用logging模块来提高程序的可读性和可维护性。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值