Python 异常机制 - Exception MechanismPython 的异常机制是一个重要的功能它允许我们在程序运行时捕获和处理错误。合理的异常处理可以提高程序的鲁棒性避免程序崩溃同时也能提供清晰的错误报告。基本概念异常是指程序执行过程中出现的错误或异常情况。当出现异常时Python 会停止当前的程序执行跳转到相应的except块处理异常。如果未处理程序将会终止。try / except / else / finally这是 Python 异常处理的基本语法结构。每个部分的作用如下try包裹可能发生异常的代码块。except当try块发生异常时except块用于捕获并处理异常。else在没有发生异常时执行的代码块通常用于处理那些在没有异常时需要执行的操作。finally无论是否发生异常都会执行的代码块通常用于资源释放如文件关闭、数据库连接断开等。try:numint(input(请输入一个数字: ))exceptValueError:print(输入无效请输入数字! )else:print(f你输入的数字是:{num})finally:print(执行完毕)自定义异常自定义异常需要继承 Python 内建的Exception类。classCustomError(Exception):def__init__(self,message):self.messagemessagesuper().__init__(self.message)# 使用自定义异常try:raiseCustomError(这是一个自定义异常!)exceptCustomErrorase:print(e)自定义异常的应用在实际的开发中通过自定义异常可以更清晰地表达错误状态。通过给异常添加更多的上下文信息可以帮助开发者更好地定位问题。# 假设我们在开发一个银行账户管理系统当用户尝试提取超过账户余额的资金时应该抛出一个自定义异常 InsufficientFundsErrorclassInsufficientFundsError(Exception):def__init__(self,balance,amount):self.balancebalence self.amountamount self.messagef账户余额{balance}不足以提取{amount}元。super().__init__(self.message)classBankAccount:def__init__(self,account_holder,balance0):self.account_holderaccount_holder self.balancebalancedefdeposit(self,amount):存款ifamount0:self.balanceamountprint(f存入{amount}元当前余额{self.balance}元。)else:print(存款金额必须大于 0 元。)defwithdraw(self,amount):取款ifamount0:print(取款金额必须大于 0 元。)returnifamountself.balance:# 抛出自定义异常raiseInsufficientFundsError(self.balance,amount)self.balance-amountprint(f成功提取{amount}元当前余额{self.balance}元。)# 测试代码accountBankAccount(Jackey Song,1000)# 存款account.deposit(500)# 尝试取款try:account.withdraw(2000)# 余额不足exceptInsufficientFundsErrorase:print(f错误:{e})虽然通过if-else语句也可以判断取款余额不足的情况但没有自定义异常的写法优雅。使用if-else错误处理往往与正常的业务逻辑混在一起这使得代码解构变得臃肿降低了代码的清晰度。而使用自定义异常能够将错误处理与正常的流程分开从而让代码更加简洁和直观。异常链raise ... from ...异常链允许我们在捕获一个异常后重新抛出一个新的异常并保留原异常的上下文。这有助于维护异常的追踪链让错误信息更加完整。defdivision(a,b):try:returna/bexceptZeroDivisionErrorase:raiseValueError(除数不能为零)fromeclassMyCustomException(Exception):def__init__(self,message):self.messagemessagesuper().__init__(self.message)defwrap():try:resultdivision(10,0)exceptValueErrorase:raiseMyCustomException(自定义异常!)frometry:wrap()exceptMyCustomExceptionase:print(f捕获到异常:{e})print(f原始异常:{e.__cause__})print(f原始异常的原始异常:{e.__cause__.__cause__})输出捕获到异常: 自定义异常! 原始异常: 除数不能为零 原始异常的原始异常: division by zero常见内置异常IndexError列表或元组索引超出范围。KeyError字典查找的键不存在。ValueError传递给函数的参数类型正确但值不符合要求。TypeError操作和函数应用于不支持的类型。FileNotFoundError尝试访问的文件不存在。ZeroDivisionError除数为零时抛出此异常。AttributeError访问不存在的对象属性。异常的捕获顺序当有多个except子句时Python 会按顺序检查异常类型首先匹配到的异常类型会被处理。要特别注意捕获顺序以避免捕获不准确的异常。try:xint(abc)exceptValueError:print(ValueError 错误)exceptException:print(捕获其他类型错误)输出将是ValueError 错误。如果交换except顺序ValueError就会被Exception捕获导致ValueError无法正常处理。assert语句assert是一种调试工具它用于检查某个条件是否成立。如果条件为False会抛出AssertionError异常。x5assertx5# 条件成立不会抛出异常assertx!5# 条件不成立会抛出 AssertionErrorassert主要用于开发和调试阶段生产环境中最好禁用 assert 语句通过python -O script.py参数。x-1assertx0,x 必须大于 0$ python test.py Traceback(most recent call last): Filetest.py, line2,inmoduleassert x0,x 必须大于 0^^^^^ AssertionError: x 必须大于0$ python-Otest.py $工程最佳实践原则不滥用except Exceptionexcept Exception会捕获所有的异常类型包括程序中的所有的错误。虽然它可以防止程序崩溃但过度使用它会使程序的错误处理变得不明确也可能掩盖真正的问题。推荐做法捕获具体的异常类型。对于已知的错误类型采用except捕获并处理。对于不确定的错误使用except Exception捕获但要及时记录日志或重新抛出。try:# 可能出错的代码passexceptValueErrorase:print(f捕获 ValueError:{e})exceptExceptionase:print(f捕获其他错误:{e})raise# 重新抛出异常用异常表达”错误状态“在一些工程中错误不仅仅是程序崩溃的信号它还应该是业务逻辑的一部分。例如当用户输入错误的参数时可以通过抛出异常来提示用户。这样的做法能让程序的错误处理变得清晰且符合业务需求。classInvalidInputError(Exception):passdefprocess_data(data):ifnotdata:raiseInvalidInputError(数据不能为空)# 正常处理数据适当的日志记录在捕获异常时记录错误日志可以帮助开发者在调试过程中找出问题。importlogging logging.basicConfig(levellogging.ERROR)try:numint(input(请输入一个数字: ))exceptValueErrorase:logging.error(f输入错误:{e})print(输入无效请输入数字)小结Python 的异常机制非常强大它不仅仅是捕获程序错误的工具还能帮助我们实现更加健壮的代码。通过合理使用try / except结构、自定义异常、异常链、以及遵循工程最佳实践我们可以提升代码的可维护性、清晰性和鲁棒性。
Part 1:Python语言核心 - 异常机制
Python 异常机制 - Exception MechanismPython 的异常机制是一个重要的功能它允许我们在程序运行时捕获和处理错误。合理的异常处理可以提高程序的鲁棒性避免程序崩溃同时也能提供清晰的错误报告。基本概念异常是指程序执行过程中出现的错误或异常情况。当出现异常时Python 会停止当前的程序执行跳转到相应的except块处理异常。如果未处理程序将会终止。try / except / else / finally这是 Python 异常处理的基本语法结构。每个部分的作用如下try包裹可能发生异常的代码块。except当try块发生异常时except块用于捕获并处理异常。else在没有发生异常时执行的代码块通常用于处理那些在没有异常时需要执行的操作。finally无论是否发生异常都会执行的代码块通常用于资源释放如文件关闭、数据库连接断开等。try:numint(input(请输入一个数字: ))exceptValueError:print(输入无效请输入数字! )else:print(f你输入的数字是:{num})finally:print(执行完毕)自定义异常自定义异常需要继承 Python 内建的Exception类。classCustomError(Exception):def__init__(self,message):self.messagemessagesuper().__init__(self.message)# 使用自定义异常try:raiseCustomError(这是一个自定义异常!)exceptCustomErrorase:print(e)自定义异常的应用在实际的开发中通过自定义异常可以更清晰地表达错误状态。通过给异常添加更多的上下文信息可以帮助开发者更好地定位问题。# 假设我们在开发一个银行账户管理系统当用户尝试提取超过账户余额的资金时应该抛出一个自定义异常 InsufficientFundsErrorclassInsufficientFundsError(Exception):def__init__(self,balance,amount):self.balancebalence self.amountamount self.messagef账户余额{balance}不足以提取{amount}元。super().__init__(self.message)classBankAccount:def__init__(self,account_holder,balance0):self.account_holderaccount_holder self.balancebalancedefdeposit(self,amount):存款ifamount0:self.balanceamountprint(f存入{amount}元当前余额{self.balance}元。)else:print(存款金额必须大于 0 元。)defwithdraw(self,amount):取款ifamount0:print(取款金额必须大于 0 元。)returnifamountself.balance:# 抛出自定义异常raiseInsufficientFundsError(self.balance,amount)self.balance-amountprint(f成功提取{amount}元当前余额{self.balance}元。)# 测试代码accountBankAccount(Jackey Song,1000)# 存款account.deposit(500)# 尝试取款try:account.withdraw(2000)# 余额不足exceptInsufficientFundsErrorase:print(f错误:{e})虽然通过if-else语句也可以判断取款余额不足的情况但没有自定义异常的写法优雅。使用if-else错误处理往往与正常的业务逻辑混在一起这使得代码解构变得臃肿降低了代码的清晰度。而使用自定义异常能够将错误处理与正常的流程分开从而让代码更加简洁和直观。异常链raise ... from ...异常链允许我们在捕获一个异常后重新抛出一个新的异常并保留原异常的上下文。这有助于维护异常的追踪链让错误信息更加完整。defdivision(a,b):try:returna/bexceptZeroDivisionErrorase:raiseValueError(除数不能为零)fromeclassMyCustomException(Exception):def__init__(self,message):self.messagemessagesuper().__init__(self.message)defwrap():try:resultdivision(10,0)exceptValueErrorase:raiseMyCustomException(自定义异常!)frometry:wrap()exceptMyCustomExceptionase:print(f捕获到异常:{e})print(f原始异常:{e.__cause__})print(f原始异常的原始异常:{e.__cause__.__cause__})输出捕获到异常: 自定义异常! 原始异常: 除数不能为零 原始异常的原始异常: division by zero常见内置异常IndexError列表或元组索引超出范围。KeyError字典查找的键不存在。ValueError传递给函数的参数类型正确但值不符合要求。TypeError操作和函数应用于不支持的类型。FileNotFoundError尝试访问的文件不存在。ZeroDivisionError除数为零时抛出此异常。AttributeError访问不存在的对象属性。异常的捕获顺序当有多个except子句时Python 会按顺序检查异常类型首先匹配到的异常类型会被处理。要特别注意捕获顺序以避免捕获不准确的异常。try:xint(abc)exceptValueError:print(ValueError 错误)exceptException:print(捕获其他类型错误)输出将是ValueError 错误。如果交换except顺序ValueError就会被Exception捕获导致ValueError无法正常处理。assert语句assert是一种调试工具它用于检查某个条件是否成立。如果条件为False会抛出AssertionError异常。x5assertx5# 条件成立不会抛出异常assertx!5# 条件不成立会抛出 AssertionErrorassert主要用于开发和调试阶段生产环境中最好禁用 assert 语句通过python -O script.py参数。x-1assertx0,x 必须大于 0$ python test.py Traceback(most recent call last): Filetest.py, line2,inmoduleassert x0,x 必须大于 0^^^^^ AssertionError: x 必须大于0$ python-Otest.py $工程最佳实践原则不滥用except Exceptionexcept Exception会捕获所有的异常类型包括程序中的所有的错误。虽然它可以防止程序崩溃但过度使用它会使程序的错误处理变得不明确也可能掩盖真正的问题。推荐做法捕获具体的异常类型。对于已知的错误类型采用except捕获并处理。对于不确定的错误使用except Exception捕获但要及时记录日志或重新抛出。try:# 可能出错的代码passexceptValueErrorase:print(f捕获 ValueError:{e})exceptExceptionase:print(f捕获其他错误:{e})raise# 重新抛出异常用异常表达”错误状态“在一些工程中错误不仅仅是程序崩溃的信号它还应该是业务逻辑的一部分。例如当用户输入错误的参数时可以通过抛出异常来提示用户。这样的做法能让程序的错误处理变得清晰且符合业务需求。classInvalidInputError(Exception):passdefprocess_data(data):ifnotdata:raiseInvalidInputError(数据不能为空)# 正常处理数据适当的日志记录在捕获异常时记录错误日志可以帮助开发者在调试过程中找出问题。importlogging logging.basicConfig(levellogging.ERROR)try:numint(input(请输入一个数字: ))exceptValueErrorase:logging.error(f输入错误:{e})print(输入无效请输入数字)小结Python 的异常机制非常强大它不仅仅是捕获程序错误的工具还能帮助我们实现更加健壮的代码。通过合理使用try / except结构、自定义异常、异常链、以及遵循工程最佳实践我们可以提升代码的可维护性、清晰性和鲁棒性。