CC++ & Algorithm

Python异常处理进阶

困难2
语言版本:C++Python
概述:学会用 try-except-else-finally 这套“安全工具”,让你的程序遇到错误也能冷静处理。

让程序不“崩溃”的秘密武器:Python异常处理进阶

小朋友,你写程序时遇到过“崩溃”吗?比如用户输入“0”作为除数,程序就直接报错停止了。或者用户不小心输入了字母“abc”,结果程序“啪”地就挂了。其实,我们可以用 异常处理 来“接住”这些错误,就像接住掉下来的杯子一样,让程序继续稳稳地运行。

今天我们学习更高级的用法:elsefinally。它们能让你的程序在遇到错误时更聪明、更体贴。

想象一下:你做化学实验,先小心倒液体(可能洒出来),如果洒了就用抹布擦(捕获异常)。如果没洒,就记录实验结果(else)。不管洒没洒,最后都要洗手(finally)。

Python 的 try-except-else-finally 就是这套流程。下面我们来一步步学会使用它。


1. 为什么需要异常处理?

程序运行的时候,可能会遇到各种“意外”:

  • 用户输入了不该输入的内容(比如“abc”当成数字)
  • 文件突然不见了
  • 网络连接中断

如果不处理,程序会直接报错并停止运行,用户会一脸懵。用异常处理,我们可以优雅地告诉用户“哪里出错了”,并且给用户重新尝试的机会。


2. 基本结构:try 和 except

最基础的是 try-except

# 让用户输入一个数字
try:
    # 用户输入的内容可能不是整数
    num = int(input("请输入一个整数:"))
except ValueError:
    # 如果输入的不是整数,就捕获这个错误
    print("你输入的不是整数哦,请重新运行!")

生活例子:就像你请朋友帮忙倒水,如果朋友没倒好洒了(异常),你就拿起抹布擦(处理)。


3. 多个 except:分别处理不同错误

一个 try 后面可以跟好几个 except,每个 except 处理一种错误类型。这样不同的问题,可以用不同的方式处理。

# 两个数字相除
try:
    a = int(input("请输入被除数:"))   # 被除数
    b = int(input("请输入除数:"))     # 除数
    result = a / b                    # 除法运算
except ValueError:
    print("输入的不是整数,请重新运行程序。")
except ZeroDivisionError:
    print("除数不能为0,请重试。")

常见错误:新手容易忘记写错误类型,写成 except: 而没有指定类型,这样虽然能捕获所有错误,但无法针对不同错误给出不同提示。尽量明确写出错误类型。


4. else:没出错时才做的事

else 块里的代码 只有没有发生异常 时才会执行。它适合放“成功后的操作”——比如打印结果、保存数据、说“恭喜”等。

# 要求用户输入两个数字做除法
try:
    a = int(input("请输入被除数:"))   # 被除数
    b = int(input("请输入除数:"))     # 除数
    result = a / b                    # 结果
except ValueError:
    print("输入的不是整数,请重新运行程序。")
except ZeroDivisionError:
    print("除数不能为0,请重试。")
else:
    # 没有发生任何异常时执行
    print("计算成功!结果是:", result)

生活例子:你考试前检查文具(try),如果发现笔没水了(except),就换一支。如果所有笔都正常(没异常),就安心考试(else)。

注意else 必须在所有 except 之后,而且不能单独存在,必须和 try 一起用。


5. finally:无论如何都要做的事

finally 块厉害的地方在于:不管有没有异常,它都会执行。哪怕 try 里写了 return 或者程序要退出了,finally 也会跑完。

finally 适合做“清理工作”——比如关闭文件、断开网络连接、打印“再见”提示等。

# 带 finally 的除法例子
try:
    a = int(input("请输入被除数:"))
    b = int(input("请输入除数:"))
    result = a / b
except ValueError:
    print("输入的不是整数。")
except ZeroDivisionError:
    print("除数不能为0。")
else:
    print("计算成功!结果是:", result)
finally:
    # 无论是否出错,都会执行
    print("程序结束,感谢使用。")

生活例子:你去游泳(可能游得好,也可能呛水),但是不管怎样,游完之后你都要去冲澡(finally)。

常见错误:把 finallyelse 搞混。记住:else 只在没异常时执行,finally 任何时候都执行。


6. 常见错误与避坑指南

  • 错误类型写错:比如把 ZeroDivisionError 写成 ZeroDivisionErrorr(多了一个r),程序会报错说“这个错误没定义”。一定要用 Python 内置的错误名称。

  • except 后面不写错误类型except: 会捕获所有异常,但这样你就不知道具体是什么错误,不利于调试。最好明确写出。

  • else 的位置不对else 必须在所有 except 之后,不能放在 except 前面。

  • finally 里写 return:如果你在 finally 里写了 return,它会覆盖 tryexcept 里的 return,导致意外结果。一般不要在 finally 里写 return。


7. 完整示例:让用户直到输入正确为止

把前面学的结合起来,做一个“防崩溃”的除法计算器。用户输入错误可以重试,直到成功为止。

# 提示用户直到输入正确,完成除法
while True:                     # 无限循环,直到正确才退出
    try:
        # 用户输入两个数字
        a = int(input("请输入被除数:"))   # 被除数,整数
        b = int(input("请输入除数:"))     # 除数,整数
        result = a / b                    # 计算结果
    except ValueError:
        print("你输入的不是整数,请重新输入!")
    except ZeroDivisionError:
        print("除数不能为0,请重新输入!")
    else:
        # 没有异常时执行,打印结果并退出循环
        print(f"计算成功!{a} ÷ {b} = {result}")
        break                   # 跳出 while 循环
    finally:
        # 每次循环结束都打印分隔线(无论成功还是失败)
        print("--- 本次尝试结束 ---")

print("程序正常退出,谢谢使用!")

运行这个程序,即使输错多次,也不会崩溃,会一直提示直到正确为止。


8. 相关指引:还能学哪些?

  • 抛出异常:用 raise 手动制造异常,比如当用户输入负数时,主动抛出 ValueError
  • 自定义异常:你可以创建自己的异常类,比如 AgeError(年龄错误),让错误信息更具体。
  • 异常处理的最佳实践:不要用异常处理代替普通的条件判断(比如检查除数是否为0可以用 if b == 0 提前判断),异常处理只用于“真正意外”的情况。

掌握了异常处理,你的程序就能从“玻璃人”变成“铁人”——遇到问题不会轻易倒下,而是给你机会改正。快去试试吧!

例题精讲

1单选题

在Python中,以下关于try-except-else-finally语句的执行顺序描述中,哪一项是正确的?

A当try块没有异常时,先执行else块,再执行finally块
B当try块有异常时,先执行except块,再执行else块,最后执行finally块
Cfinally块只在try块没有异常时执行
Delse块在无论是否有异常都会执行
2判断题

在Python中,自定义异常类必须直接或间接继承自BaseException类。

3填空题
阅读以下代码,当输入为'0'时,输出是什么?请填写。
def divide(x, y):
    try:
        result = x / y
    except ZeroDivisionError:
        print('除数不能为0')
        raise
    else:
        print('计算成功')
    finally:
        print('执行完毕')

try:
    divide(10, 0)
except ZeroDivisionError:
    print('捕获到异常')

输出顺序:
除数不能为0
___
捕获到异常
4单选题

在Python中,使用raise ... from ...语句的主要目的是什么?

A直接抛出一个新异常而不保留原始异常信息
B将原始异常作为新异常的原因(cause)进行链式关联
C同时抛出两个不同的异常
D抑制异常链,使新异常看起来与原始异常无关
5判断题

在Python的try-finally语句中,如果finally块中包含了return语句,则会覆盖try块中的return语句。