异常处理
大家好!这个章节我们要讨论的主题是异常处理。在程序中,错误是不可避免的,尤其是在面对外部输入和文件操作时,可能会发生各种不可预见的问题。异常处理就是为了应对这些问题,让程序在遇到错误时,不是直接崩溃,而是能通过一些处理来避免程序中断,甚至还能提供有用的错误信息,帮助我们更好地定位问题。
简介
编写程序时,即使语句或表达式使用了正确的语法,执行时仍可能触发错误。执行时检测到的错误称为异常,大多数异常不会被程序处理,程序会中断运行,并抛出异常信息。
如果不想发生异常时,程序被中断执行,可以编写程序处理选定的异常。
在编程中,我们有时会遇到即使语法正确,程序在执行时也会出现问题的情况。这些问题就是我们所说的“异常”。异常一般会叫做 exception,其实就是指在程序执行过程中发生的错误。异常通常会导致程序中止执行,但我们可以通过 抛出异常 来主动触发某些错误,或者通过 捕获异常 来处理它们。当程序遇到异常时,默认的行为是中断程序的执行,并抛出异常信息。然而,有时候我们并不希望程序因为一个小错误就直接崩溃,这时,我们可以通过异常处理机制来捕捉并处理这些异常,确保程序可以继续运行或者优雅地终止。
捕获异常
Python 使用 try/except语句捕获异常。
try/except 语句用来检测 try 语句块中的错误,从而让 except 语句捕获异常信息并处理。
如果你不想在异常发生时结束你的程序,只需在 try 里捕获它。
file = open("data.txt","r")
try:
# 写入数据时可能会有问题
file.write("写入的数据")
except IOError as err:
print("文件不能写入", err)
file.close()
在 Python 中,最常用的捕获异常方式是 try-except 语句。你可以把它想象成一个“防护罩”:当代码在 try 块中运行时,如果出现异常,程序就不会崩溃,而是会跳转到 except 块,去处理这个异常。这样,我们就可以控制程序在错误发生时的行为。举个例子,我们有一个读取文件的操作,而读取文件时可能会出现文件不存在、权限不足等问题。通过 try except,我们就可以捕捉这些错误并给出提示,而不是让程序直接崩溃。在这个例子中,如果打开文件或者写入文件时发生了 IOError,except 会捕捉到这个异常并输出相应的错误信息。
捕捉多个异常
如果一段代码可能会发生多种异常,并想在程序中都想处理,可以使用多个 except 分别捕捉异常。
可以捕捉 Exception 异常类型来处理所有的异常,如果有多个时,必须放在最后捕捉该异常,否则无法处理到其它异常。
file = open("data.txt","r")
try:
# 写入数据时可能会有问题
# file.write("写入的数据")
# print(a)
# print(3 / 0)
# print([][10])
print("hello" + 100)
except IOError as err:
print("文件不能写入", err)
except NameError:
print("标识符没有定义")
except ZeroDivisionError:
print("除数不能为0")
except IndexError:
print("下标越界了")
except Exception:
print("程序运行出错,请检查代码")
file.close()
有时候,一段代码可能会出现多种异常类型,而我们又希望分别处理这些异常。Python 提供了多种方法来捕捉不同类型的异常,最简单的方式是写多个 except 块,针对不同的错误类型做出不同的处理。举个例子,假设我们在文件操作时既有可能遇到文件写入问题,也有可能因为除数为零而出错。我们可以通过多个 except 块来分别处理这些问题。在这个例子中,我们有多个 except,每个 except 都对应一种可能的错误类型。如果有多个错误发生,Python 会按照顺序依次检查各个 except 块,直到找到匹配的异常类型并进行处理。
else 操作
Python 使用 else 在处理在代码无异常时的后续操作。
try:
n = input("请输入一个数字:")
num = int(n)
except Exception:
print("元素无法转换为数字")
else:
print("转换后成功",num)
除了 try 和 except,Python 还提供了 else 块,这个块的作用是当 try 中的代码没有出现异常时,执行 else 中的代码。一般来说,else 块用来放置那些在没有错误的情况下需要执行的代码。举个简单的例子,如果我们在尝试将用户输入的字符串转换为整数时,发生了异常(比如用户输入了字母),就会进入 except 块,输出错误信息。如果没有错误,我们就可以执行 else 块,告知用户转换成功。在这个例子中,如果输入的是一个数字,else 块会被执行,输出转换成功的提示;如果输入的是非数字内容,则会跳转到 except 块,输出错误信息。
finally 操作
Python 使用 finally 处理无论异常是否发异,都要执行的代码,一般用来完成清理工作。
try:
file = open("data.txt","r")
# file.write("A")
except Exception:
print("文件操作报错")
finally:
print("文件已关闭")
file.close()
有时候,我们希望无论程序是否发生异常,都要执行一些清理工作,比如关闭文件、释放资源等。这个时候就可以使用 finally 块。finally 中的代码不管程序是否发生异常都会被执行,常常用于文件关闭、数据库连接断开等场景。在这个例子中,无论文件操作是否成功,finally 中的代码都会被执行,确保文件被正确关闭。
抛出异常
抛出异常 就是主动生成一个异常对象,并将其传递到调用栈中,这样程序就会跳转到相应的 except 代码块,或者终止执行并显示错误信息。抛出异常通常使用 raise 语句。
raise Exception("错误消息")
抛出异常就是主动生成一个异常对象,然后把它传递到调用栈当中。这样程序执行到这里就会跳转到相应的 except 代码块,或者直接终止执行并显示错误信息。想要抛出异常使用 raise 语句就可以了。比如这个例子中 raise Exception("错误消息") 将会抛出一个 Exception 异常,并附带一个错误消息。当异常被抛出来的时候,程序就会停止执行代码块,一直到捕获到这个异常或者程序终止。
抛出指定的异常类型
可以通过 raise 语句抛出不同类型的异常。例如,ValueError、TypeError、FileNotFoundError 等。还可以自定义异常类,抛出自己的异常类型。
def check_age(age):
if age < 0:
# 抛出 ValueError 异常
raise ValueError("年龄不能为负数")
print(f"年龄是 {age}")
# 调用函数
try:
check_age(-5) # 会抛出 ValueError 异常
except ValueError as e:
print(f"捕获到异常:{e}")
使用 raise 语句可以抛出不同类型的异常。例如,ValueError、TypeError、FileNotFoundError 等。还可以自定义异常类,抛出自己的异常类型。
自定义异常
- 继承 Exception 类: Python 中的异常类都是继承自内置的 Exception 类,因此我们可以通过继承 Exception 类来创建自己的异常类。
- 添加构造方法(
__init__): 自定义异常类通常会添加构造方法,允许我们在抛出异常时传递额外的信息,比如错误消息或其他重要的上下文信息。 - 可选:重写
__str__或__repr__方法:可以重写__str__方法来定制异常的输出格式,让错误信息更易于理解。
# 自定义异常类
class NegativeAmountError(Exception):
def __init__(self, message="订单金额不能为负!"):
# 异常消息
self.message = message
# 调用父类构造函数
super().__init__(self.message)
# 函数:处理订单
def process_order(amount):
if amount < 0:
# 抛出自定义异常
raise NegativeAmountError(f"无效金额:{amount}")
print(f"订单金额:{amount} 处理成功!")
# 使用自定义异常
try:
# 传递负数金额,会触发自定义异常
process_order(-10)
except NegativeAmountError as e:
print(f"错误: {e}")
当我们需要为特定的错误情形提供更加明确的错误信息时,通常会自定义异常。自定义异常允许我们创建自己的异常类,从而根据具体业务需求来处理特定的错误。Python 中的异常类都是继承自内置的 Exception 类,因此我们可以通过继承 Exception 类来创建自己的异常类。自定义异常类通常会添加构造方法,允许我们在抛出异常时传递额外的信息,比如错误消息或其他重要的上下文信息。可以重写 __str__ 方法来定制异常的输出格式,让错误信息更易于理解。
总结
- 捕捉异常
- 抛出异常
- 自定义异常
最后来总结一下。这个章节我们学习了 Python 中的异常处理,包括如何捕获一场,如何抛出异常和如何自定义异常。掌握这些异常处理的技巧,能让你写出更健壮、更稳定的程序,避免程序因为小错误而崩溃。