Python中的异常处理以及自定义异常类型

Python中的异常和处理以及使用

异常

程序在运行过程当中,不可避免的会出现一些错误,比如:
使用了没有赋值过的变量
使用了不存在的索引
除0

这些错误在程序中,我们称其为异常。
程序运行过程中,一旦出现异常将会导致程序立即终止,异常以后的代码全部都不会执行!

处理异常

程序运行时出现异常,目的并不是让我们的程序直接终止!
Python是希望在出现异常时,我们可以编写代码来对异常进行处理!

try语句

try:
    代码块(可能出现错误的语句)
except 异常类型 as 异常名:
    代码块(出现错误以后的处理方式)
except 异常类型 as 异常名:
    代码块(出现错误以后的处理方式)
except 异常类型 as 异常名:
    代码块(出现错误以后的处理方式)
else:
    代码块(没出错时要执行的语句)    
finally:
    代码块(该代码块总会执行)

try是必须的 else语句有没有都行
except和finally至少有一个

可以将可能出错的代码放入到try语句,这样如果代码没有错误,则会正常执行,
如果出现错误,则会执行expect子句中的代码,这样我们就可以通过代码来处理异常
避免因为一个异常导致整个程序的终止

异常的传播(抛出异常)

当在函数中出现异常时,如果在函数中对异常进行了处理,则异常不会再继续传播,
如果函数中没有对异常进行处理,则异常会继续向函数调用处传播,
如果函数调用处处理了异常,则不再传播,如果没有处理则继续向调用处传播
直到传递到全局作用域(主模块)如果依然没有处理,则程序终止,并且显示异常信息

当程序运行过程中出现异常以后,所有的异常信息会被保存一个专门的异常对象中,
而异常传播时,实际上就是异常对象抛给了调用处
比如 : ZeroDivisionError类的对象专门用来表示除0的异常
NameError类的对象专门用来处理变量错误的异常
…等等

当程序运行时,如果没有进行异常处理,异常会一直传播,直到传递到全局作用域(主模块),此时程序会终止并显示异常信息。

下面是一个示例:

def fn():
    raise ValueError("这是一个自定义的异常")

def main():
    try:
        fn()
    except ValueError as e:
        print("发生了异常:", e)

main()

print("程序结束")

在上面的代码中,fn()函数中使用raise语句抛出了一个ValueError异常,并指定了异常信息为"这是一个自定义的异常"。在main()函数中,使用try-except语句捕获了ValueError异常,并打印出异常信息。最后,输出"程序结束"。

抛出异常

可以使用 raise 语句来抛出异常,
raise语句后需要跟一个异常类 或 异常的实例

当在代码中使用异常处理时,我们可以使用raise语句来引发自定义的异常或重新引发已捕获的异常。

下面是一个示例:

def divide(x, y):
    try:
        if y == 0:
            raise ZeroDivisionError("除数不能为零")
        result = x / y
    except ZeroDivisionError as e:
        print(e)
        raise  # 重新引发已捕获的异常
    else:
        print("结果:", result)

try:
    divide(10, 2)
    divide(10, 0)
except ZeroDivisionError as e:
    print("捕获异常:", e)

在上述代码中,当除数为零时,我们通过raise语句引发了内置的ZeroDivisionError异常,并传入错误消息。同时,在except ZeroDivisionError块中使用raise语句重新引发已捕获的异常,以便在外部继续处理该异常。

在使用引发异常时,我们可以选择传递一个异常类的实例或使用类名直接引发该异常。在本例中,我们使用了后者,即raise ZeroDivisionError("除数不能为零")

在主代码块中,我们用try-except来捕获ZeroDivisionError异常,并打印出捕获的异常信息。这样就能够处理由divide()函数引发的异常。

输出如下:

结果: 5.0
division by zero
捕获异常: division by zero

通过使用raise语句,我们可以在代码中显式地引发异常,并根据需要进行处理或传递。这使得异常处理更加灵活和可控,有助于编写健壮的代码。

try-except语句

在Python中,我们可以使用try-except语句来捕获并处理指定类型的异常。除了捕获特定类型的异常外,我们还可以使用try-except语句的多个except块来分别处理不同类型的异常。

下面是一个示例:

def divide(x, y):
    try:
        result = x / y
        print("结果:", result)
    except ZeroDivisionError:
        print("除数不能为零")
    except TypeError:
        print("类型错误:无法进行除法运算")
    except ValueError:
        print("数值错误")
    
divide(10, 2)
divide(10, 0)
divide(10, "2")

在上述代码中,divide()函数用于计算两个数的除法并打印结果。在try块中进行除法运算,如果出现异常,则根据异常类型执行相应的except块。

第一次调用divide(10, 2)时,由于除数不为零,没有触发异常,因此会输出结果。

第二次调用divide(10, 0)时,除数为零,触发了ZeroDivisionError异常,程序会执行对应的except ZeroDivisionError块,打印"除数不能为零"。

第三次调用divide(10, "2")时,除数为字符串类型,无法进行除法运算,触发了TypeError异常,程序会执行对应的except TypeError块,打印"类型错误:无法进行除法运算"。

输出如下:

结果: 5.0
除数不能为零
类型错误:无法进行除法运算

通过使用多个except块,可以针对不同的异常类型编写特定的处理代码,使程序能够更准确地处理各种可能的异常情况。这样可以提高程序的健壮性和可靠性。

finally 语句

除了使用try-except语句来处理异常以外,还可以使用finally子句来定义无论是否发生异常都需要执行的代码块。finally子句中的代码块会在try块中的代码执行完成后无论是否发生异常都会被执行。

下面是一个示例:

def divide(x, y):
    try:
        result = x / y
    except ZeroDivisionError:
        print("除数不能为零")
    finally:
        print("执行finally代码块")
    
divide(10, 2)
divide(10, 0)

在上述代码中,divide()函数用于计算两个数的除法并打印结果,其中使用try-except-finally语句来处理异常。

第一次调用divide(10, 2)时,由于除数不为零,没有触发异常,因此会输出结果并执行finally代码块。输出如下:

结果: 5.0
执行finally代码块

第二次调用divide(10, 0)时,除数为零,触发了ZeroDivisionError异常,异常被捕获并打印错误信息,然后继续执行finally代码块。输出如下:

除数不能为零
执行finally代码块

可以看到,不论是否发生异常,finally代码块中的代码都会被执行。

finally子句通常用于释放资源,例如关闭文件、释放锁等。它确保不论是否发生异常,都会执行一些必要的清理操作,以保证程序的稳定性和安全性。

else语句

除了try-except语句外,你还可以使用else子句来定义在try块中没有发生任何异常时执行的代码块。

下面是一个示例:

def divide(x, y):
    try:
        result = x / y
    except ZeroDivisionError:
        print("除数不能为零")
    else:
        print("结果:", result)
    
divide(10, 2)
divide(10, 0)

在上述代码中,divide()函数用于计算两个数的除法并打印结果。在try块中进行除法运算,如果出现除以零的异常,则程序会执行对应的except ZeroDivisionError块,打印"除数不能为零"。如果没有发生异常,程序会执行else子句中的代码块,打印结果。

第一次调用divide(10, 2)时,由于除数不为零,没有触发异常,因此会输出结果。

第二次调用divide(10, 0)时,除数为零,触发了ZeroDivisionError异常,程序会执行对应的except ZeroDivisionError块,打印"除数不能为零",而不会执行else子句中的代码块。

输出如下:

结果: 5.0
除数不能为零

通过使用else子句,可以将正常处理逻辑放在else中,使代码更加清晰和简洁。这样,我们可以清楚地区分异常处理和正常逻辑处理,提高代码的可读性和可维护性。

自定义异常类型

另外,如果我们需要自定义异常类型,可以通过继承内置的Exception类来创建新的异常类型,并在需要抛出异常时使用该类型。

下面是一个示例:

class MyError(Exception):
    def __init__(self, msg):
        self.msg = msg

def divide(x, y):
    try:
        if y == 0:
            raise MyError("除数不能为零")
        result = x / y
    except MyError as e:
        print(e.msg)
    else:
        print("结果:", result)
    finally:
        print("执行清理操作")

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

在上述代码中,我们通过继承Exception类创建了一个新的异常类型MyError,并在其构造函数中传入一个错误消息。在divide()函数中,我们在除以零时抛出了自定义的异常MyError,并捕获并处理这个异常。如果没有发生异常,会执行else子句中的代码块,打印结果。无论是否发生异常,最后都会执行finally子句中的代码块,打印"执行清理操作"。

输出如下:

结果: 5.0
执行清理操作
除数不能为零
执行清理操作

通过自定义异常类型,我们可以更好地组织和管理自己的代码,提高代码的可读性和可维护性。同时,也能够更加灵活地处理不同类型的异常情况,满足不同的业务需求。

总结

本文介绍了Python中异常的使用和处理。异常是在程序执行期间发生的错误或异常情况,可以通过使用try-except语句来捕获和处理异常。

文章首先解释了什么是异常,并且描述了异常处理的重要性。接着,介绍了如何使用try-except语句来捕获并处理异常。try块中的代码可能引发异常,而except块中的代码将只有在相应的异常发生时才会执行。

文章还提到了finally语句,它允许我们定义一段无论是否发生异常都会执行的代码块。这对于确保资源的释放或清理非常有用。

此外,文章还介绍了else语句,它可以用于指定在try块中没有引发异常时执行的代码。这样我们可以根据是否发生异常来采取不同的行动。

最后,文章也提到了自定义异常类型的重要性和使用方法。通过定义自己的异常类,我们可以更好地组织和处理特定的异常情况,使代码更具可读性和可维护性。

通过本文的介绍,读者可以了解到如何在Python中处理异常以及如何利用异常机制编写更健壮的代码。同时,熟悉异常处理的相关概念和语法将帮助读者更好地调试和处理程序中的错误情况。

猜你喜欢

转载自blog.csdn.net/qq_41308872/article/details/132857725