零基础学 Python 第13章 | 异常处理:try-except 让程序不崩溃
本章摘要
- 核心目标:掌握 try-except 异常处理机制,让程序遇到错误不崩溃、继续运行
- 核心知识点:try-except 基本结构、捕获多种异常、as 获取异常信息、else 子句、finally 子句、常见异常类型
- 实操产出:安全除法计算器,处理除零、非数字输入等异常并允许重试
- 前置基础:第12章文件读写、第5章 while 循环、第3章 if 条件判断
一、写在前面
上一章你学会了文件读写,能用 Python 读取配置、保存数据了。但你一定遇到过这种情况:程序打开一个不存在的文件,或者读到一半编码出问题——然后整个程序直接崩掉,屏幕上刷出一大堆红色报错信息。
这种"程序运行中途出错就崩溃"的行为,在 Python 里叫异常(Exception)。异常不是 Bug,而是程序运行时遇到的意外情况:用户输入了字母但你期望数字、除数是零、文件路径写错了……这些都会触发异常。
本章教你用 try-except 语句捕获异常——程序遇到错误时不再崩溃,而是优雅地处理它、提示用户、继续运行。这是写出健壮程序的关键技能。
二、什么是异常
先看一个最常见的异常——除以零:
# 除以零会直接崩溃
result = 10 / 0
print("计算完成")
运行结果:
ZeroDivisionError: division by zero
程序在 10 / 0 这一行就崩了,后面的 print("计算完成") 根本没机会执行。这就是异常的威力:一旦触发,程序立即停止。
再看一个——把字符串当数字用:
# 取消注释运行会触发 ValueError
# age = int("十八岁")
# print(age)
Python 会报 ValueError: invalid literal for int() with base 10: '十八岁',意思是你想把"十八岁"这个字符串转成整数,Python 转不了。
异常的本质:Python 遇到无法处理的操作时,抛出一个异常对象。如果不处理它,程序就崩溃。处理了它,程序就能继续跑。
三、try-except 基本结构
try-except 的用法很简单:把可能出错的代码放进 try 块,出错后的处理逻辑放进 except 块。
基本语法:
try:
# 可能出错的代码
result = 10 / 0
except:
# 出错后执行这里
print("出错了,但程序不会崩溃")
print("程序继续运行")
运行结果:
出错了,但程序不会崩溃
程序继续运行
try 块中的代码如果正常执行,except 块就被跳过;如果 try 块中出错了,程序不崩溃,跳到 except 块执行处理逻辑。
四、捕获特定异常
直接写 except: 会捕获所有异常,但这不是好习惯——可能把不该忽略的错误也吞掉了。更好的做法是指定异常类型,只捕获你预期会发生的错误。
4.1 捕获指定异常
try:
result = 10 / 0
except ZeroDivisionError:
print("除数不能为零")
运行结果:
除数不能为零
只有 ZeroDivisionError 会被捕获,其他类型的异常仍然会让程序崩溃。
4.2 捕获多种异常
一段代码可能触发不同类型的异常,你可以同时指定多个异常类型:
try:
num = int(input("请输入一个数字:"))
result = 100 / num
print(f"结果是:{result}")
except ValueError:
print("输入的不是有效数字")
except ZeroDivisionError:
print("除数不能为零")
运行效果:
请输入一个数字:abc
输入的不是有效数字
请输入一个数字:0
除数不能为零
请输入一个数字:4
结果是:25.0
用户输入字母时触发 ValueError,输入 0 时触发 ZeroDivisionError,每种异常都有对应的提示,程序不会崩溃。
4.3 一个 except 捕获多种异常
如果多种异常的处理逻辑相同,可以用元组合并:
try:
num = int(input("请输入一个数字:"))
result = 100 / num
except (ValueError, ZeroDivisionError):
print("输入有误,请重新输入有效数字")
五、as 获取异常信息
有时候你不仅想告诉用户"出错了",还想把具体的错误信息显示出来。用 as 关键字可以把异常对象赋值给一个变量:
try:
num = int("十八岁")
except ValueError as e:
print(f"转换失败,错误信息:{e}")
运行结果:
转换失败,错误信息:invalid literal for int() with base 10: '十八岁'
e 就是异常对象,直接打印它会输出 Python 的原始错误描述。这在调试程序时非常有用——既处理了异常,又保留了错误细节。
习惯写法:异常变量通常用
e或err,表示 error(错误)。
六、else 子句
else 子句放在所有 except 后面,只有 try 块没有发生任何异常时才会执行。
try:
num = int(input("请输入年龄:"))
except ValueError:
print("请输入数字")
else:
# try 块没出错才会执行这里
print(f"你的年龄是 {num} 岁")
if num >= 18:
print("已成年")
else:
print("未成年")
运行效果:
请输入年龄:20
你的年龄是 20 岁
已成年
请输入年龄:abc
请输入数字
else的价值:把"成功后的逻辑"和"可能出错的代码"分开,结构更清晰。如果都塞进try块里,try 块中后续代码的异常也会被捕获,可能掩盖真正的问题。
七、finally 子句
finally 子句放在最后,无论是否发生异常都会执行。它通常用于清理工作,比如关闭文件、释放资源。
try:
f = open("data.txt", "r", encoding="utf-8")
content = f.read()
print(content)
except FileNotFoundError:
print("文件不存在")
finally:
# 不管有没有出错,都要关闭文件
print("执行清理工作")
运行效果(文件存在时):
(文件内容)
执行清理工作
运行效果(文件不存在时):
文件不存在
执行清理工作
finally最经典的场景就是文件操作:不管读取成功还是失败,文件都应该被关闭。后面学到数据库操作、网络请求时,finally也是标配。
八、try-except-else-finally 完整结构
把四个子句组合在一起,就是完整的异常处理结构:
try:
# 1. 可能出错的代码
num = int(input("请输入一个数字:"))
result = 100 / num
except ValueError as e:
# 2. 捕获 ValueError
print(f"输入错误:{e}")
except ZeroDivisionError as e:
# 3. 捕获 ZeroDivisionError
print(f"计算错误:{e}")
else:
# 4. 没出错才执行
print(f"计算结果:{result}")
finally:
# 5. 无论如何都执行
print("---本次计算结束---")
执行顺序总结:
| 情况 | try | except | else | finally |
|---|---|---|---|---|
| try 没出错 | ✅ 执行 | ❌ 跳过 | ✅ 执行 | ✅ 执行 |
| try 出错了 | 执行到出错处 | ✅ 匹配的执行 | ❌ 跳过 | ✅ 执行 |
记住一个口诀:try 试错、except 兜底、else 成功后做事、finally 收尾必跑。
九、常见异常类型速查
Python 内置了数十种异常类型,新手阶段最常见的有这 6 种:
| 异常类型 | 触发场景 | 示例代码 |
|---|---|---|
ValueError |
值类型不对,如 int("abc") |
int("hello") |
TypeError |
类型不支持该操作,如数字+字符串 | 1 + "2" |
ZeroDivisionError |
除以零 | 10 / 0 |
FileNotFoundError |
打开不存在的文件 | open("不存在.txt") |
IndexError |
列表索引越界 | [1, 2, 3][10] |
KeyError |
字典键不存在 | {"a": 1}["b"] |
每种异常的触发示例:
# 1. ValueError:值无法转换
# 取消注释运行会触发 ValueError
# int("hello")
# 2. TypeError:类型不兼容
# 取消注释运行会触发 TypeError
# result = 1 + "2"
# 3. ZeroDivisionError:除以零
# 取消注释运行会触发 ZeroDivisionError
# result = 10 / 0
# 4. FileNotFoundError:文件不存在
# 取消注释运行会触发 FileNotFoundError
# f = open("不存在.txt")
# 5. IndexError:索引越界
# 取消注释运行会触发 IndexError
# names = ["小明", "小红"]
# print(names[10])
# 6. KeyError:字典键不存在
# 取消注释运行会触发 KeyError
# d = {"name": "小明"}
# print(d["phone"])
这 6 种异常覆盖了新手阶段 90% 的报错场景。遇到红色报错信息时,先看异常类型名,就能快速定位问题。
十、主动抛出异常
除了被动等异常发生,你还可以用 raise 关键字主动抛出异常。当用户的数据不符合业务规则时,主动报错比默默返回错误结果更安全:
def set_age(age):
if age < 0 or age > 150:
raise ValueError("年龄必须在 0-150 之间")
print(f"年龄设置为 {age}")
# 正常调用
set_age(18) # 年龄设置为 18
# 触发异常
# 取消注释运行会触发 ValueError
# set_age(-5)
raise 抛出的异常和自然触发的异常完全一样,也可以用 try-except 捕获:
try:
set_age(-5)
except ValueError as e:
print(f"设置失败:{e}")
运行结果:
设置失败:年龄必须在 0-150 之间
raise在写函数时特别有用:在函数入口检查参数合法性,不合法就抛异常,把问题暴露在最早的位置。
十一、Scratch 积木对照
| Scratch | Python | 说明 |
|---|---|---|
| 程序报错直接闪退,无法处理 | try-except |
Python 能捕获异常并继续运行,Scratch 报错即崩溃 |
# Scratch 报错直接闪退 → Python 用 try-except 捕获继续运行
try:
num = int(input("请输入数字:"))
print(100 / num)
except (ValueError, ZeroDivisionError) as e:
print(f"输入有误:{e},请重试")
在 Scratch 里,如果你的积木逻辑出问题(比如除以零),程序会直接卡住或闪退,没有"先拦住错误再处理"的机制。Python 的 try-except 让你可以在错误发生时拦截它、处理它,程序照常运行。
十二、综合实战:安全除法计算器
综合运用 try-except、input 输入、int 类型转换、while 循环、if 条件判断,写一个除法计算器:用户输入两个数字做除法,处理除零错误、非数字输入等异常,出错后允许重试。
# ========================================
# 安全除法计算器
# ========================================
print("=" * 40)
print(" 安全除法计算器 v1.0")
print("=" * 40)
while True:
print()
print("输入两个数字,我来帮你算除法")
print("输入 'q' 退出程序")
print("-" * 30)
# 获取第一个数字
num1_input = input("请输入被除数:")
if num1_input == "q":
print("再见!")
break
# 获取第二个数字
num2_input = input("请输入除数:")
if num2_input == "q":
print("再见!")
break
try:
# 尝试转换为浮点数并计算
num1 = float(num1_input)
num2 = float(num2_input)
result = num1 / num2
except ValueError:
# 输入的不是数字
print("⚠️ 输入有误:请输入有效的数字,不要输入字母或符号")
continue
except ZeroDivisionError:
# 除数为零
print("⚠️ 计算有误:除数不能为零")
continue
else:
# 计算成功,输出结果
print(f"✅ {num1} ÷ {num2} = {result}")
finally:
# 每次计算结束都打印分隔线
print("-" * 30)
运行效果:
========================================
安全除法计算器 v1.0
========================================
输入两个数字,我来帮你算除法
输入 'q' 退出程序
------------------------------
请输入被除数:100
请输入除数:abc
⚠️ 输入有误:请输入有效的数字,不要输入字母或符号
------------------------------
输入两个数字,我来帮你算除法
输入 'q' 退出程序
------------------------------
请输入被除数:100
请输入除数:0
⚠️ 计算有误:除数不能为零
------------------------------
输入两个数字,我来帮你算除法
输入 'q' 退出程序
------------------------------
请输入被除数:100
请输入除数:4
✅ 100.0 ÷ 4.0 = 25.0
------------------------------
分步拆解:
while True循环:让计算器持续运行,用户可以反复计算,直到输入q退出(while循环第5章已学)- 两次
input获取输入:分别读取被除数和除数,输入q可以随时退出 try块做转换和计算:float()把字符串转成浮点数,再做除法。这两步是最容易出错的——输入字母会触发ValueError,除数为零会触发ZeroDivisionErrorexcept ValueError:捕获非数字输入,提示用户重新输入,用continue跳回循环开头重试except ZeroDivisionError:捕获除零错误,同样提示并重试else块:只有计算成功时才执行,输出格式化结果finally块:不管成功还是失败,都打印分隔线,让每次计算的输出之间有清晰的视觉分隔continue关键字:出错后不用从头开始循环,continue直接跳到下一次循环,让用户重新输入
这个案例体现了异常处理的核心思想:不是消灭错误,而是优雅地应对错误。程序不会因为用户输入错误就崩溃,而是给出友好提示,让用户继续使用。
十三、常见报错速查表
| 报错信息 | 出现场景 | 原因 | 解决方法 |
|---|---|---|---|
ValueError: invalid literal for int() with base 10: 'xxx' |
int() 转换 |
字符串内容不是纯数字 | 先用 isdigit() 检查或用 try-except 捕获 |
TypeError: unsupported operand type(s) for +: 'int' and 'str' |
运算 | 数字和字符串直接相加 | 用 str() 或 int() 统一类型 |
ZeroDivisionError: division by zero |
除法运算 | 除数为 0 | 除法前检查除数是否为 0 或用 try-except 捕获 |
FileNotFoundError: [Errno 2] No such file or directory: 'xxx' |
open() 打开文件 |
文件路径不存在 | 先用 os.path.exists() 检查或用 try-except 捕获 |
IndexError: list index out of range |
列表取值 | 索引超出列表长度 | 先用 len() 检查长度或用 try-except 捕获 |
KeyError: 'xxx' |
字典取值 | 键不存在 | 改用 dict.get(key) 安全取值 |
十五、本章小结
本章你掌握了 Python 异常处理的完整体系:
- 异常的本质——程序运行时遇到意外情况会抛出异常,不处理就崩溃
try-except基本结构——try放可能出错的代码,except放出错后的处理逻辑- 捕获特定异常——用异常类型名精确捕获,避免吞掉不该忽略的错误
as获取异常信息——except ValueError as e把错误对象赋值给变量,方便调试else子句——try 没出错才执行,把成功逻辑和试错逻辑分离finally子句——无论如何都执行,用于关闭文件、释放资源等清理工作- 常见异常类型——
ValueError、TypeError、ZeroDivisionError、FileNotFoundError、IndexError、KeyError,覆盖新手阶段绝大多数报错
异常处理是程序从"能跑"到"健壮"的关键一步。真实项目中,所有涉及用户输入、文件操作、网络请求的代码都应该用 try-except 保护起来。
往期回顾:
零基础学 Python 第1章 | 全平台装环境 + VS Code 配置 + 第一个 Hello World
零基础学 Python 第2章 | print 输出 + 变量赋值 + input 交互输入
零基础学 Python 第3章 | 条件判断:if / elif / else
零基础学 Python 第 4 章 | for 循环与 range():让程序帮你重复干活
零基础学 Python 第 5 章 | while 循环与循环嵌套:让程序看着条件自己干活
零基础学 Python 第 6 章 | 元组与集合:不可变数据与自动去重
零基础学 Python 第7章 | 字典 dict:键值对存储
零基础学 Python 第9章 | 函数基础:def、参数与返回值
零基础学 Python 第10章 | 函数进阶:参数灵活用法与作用域
零基础学 Python 第12章 | 文件读写:让数据持久保存
下一章预告:到现在为止你写的代码都在一个文件里。当项目变大,代码越来越长怎么办?下一章学习模块、包与第三方库——把代码拆分成多个文件,还能一键安装别人写好的工具库,让 Python 的能力指数级扩展。
文末资源区
| 资源 | 说明 |
|---|---|
| Python 官方文档 - 异常处理 | https://docs.python.org/3/tutorial/errors.html |
| Python 官方文档 - 内置异常类型 | https://docs.python.org/3/library/exceptions.html |
| 本章完整源码 | chapter13_all.py(关注梅雅达编程笔记,评论领资料) |
每节课都配套课后练习题与完整源码。代码报错、看不懂知识点,可在评论区粘贴问题,逐一解答!
欢迎关注梅雅达编程笔记,持续分享Python零基础学习内容
更多推荐




所有评论(0)