第11天:异常处理 —— 让程序不轻易崩溃
我们写的程序难免会遇到错误:用户输入了非数字内容、文件不存在、网络断开……
如果不对这些错误进行处理,程序就会崩溃(直接报错退出)。
今天来学习异常处理(Exception Handling),让程序在遇到错误时能够“优雅地”应对,而不是一崩了之。
🎯 今日目标
理解什么是异常(Exception)
掌握
try-except语句的基本语法学会捕获特定类型的异常
掌握
else和finally的用法学会主动抛出异常(
raise)了解常见的异常类型
💥 一、什么是异常?
异常是程序运行时发生的错误。当 Python 遇到它无法处理的情况时,就会抛出异常,如果没有被捕获,程序就会终止。
1.1 常见异常示例
python
# 1. 除以零 print(10 / 0) # ZeroDivisionError # 2. 访问不存在的列表索引 nums = [1, 2, 3] print(nums[5]) # IndexError # 3. 变量未定义 print(unknown) # NameError # 4. 类型不匹配 print("10" + 5) # TypeError # 5. 文件不存在 with open("不存在的文件.txt", "r") as f: # FileNotFoundError pass运行结果(第一个错误就会停止):
text
ZeroDivisionError: division by zero
💡 一旦发生异常,程序就会立即停止,后面的代码不会执行。
🛡️ 二、try-except语句:捕获异常
2.1 基本语法
python
try: # 可能会出错的代码 可能存在异常的代码 except: # 出错后执行的代码 处理异常的代码
2.2 简单例子
python
try: num = int(input("请输入一个数字: ")) result = 10 / num print(f"结果是: {result}") except: print("输入有误,请确保输入的是非零数字")运行示例:
text
请输入一个数字: 0 输入有误,请确保输入的是非零数字
💡 如果用户输入
0或非数字,程序不会崩溃,而是输出友好的提示。
🎯 三、捕获特定类型的异常
上面的写法虽然简单,但会捕获所有异常。更好的做法是针对不同类型的异常做不同处理。
3.1 捕获指定异常
python
try: num = int(input("请输入一个数字: ")) result = 10 / num print(f"结果是: {result}") except ValueError: print("❌ 错误:请输入有效的数字") except ZeroDivisionError: print("❌ 错误:不能除以零")运行示例:
text
请输入一个数字: abc ❌ 错误:请输入有效的数字
text
请输入一个数字: 0 ❌ 错误:不能除以零
3.2 捕获多个异常(元组写法)
python
try: num = int(input("请输入一个数字: ")) result = 10 / num print(f"结果是: {result}") except (ValueError, ZeroDivisionError): print("❌ 输入错误:请输入非零的有效数字")3.3 获取异常对象(获取具体错误信息)
python
try: num = int(input("请输入一个数字: ")) result = 10 / num print(f"结果是: {result}") except ValueError as e: print(f"❌ 类型错误: {e}") except ZeroDivisionError as e: print(f"❌ 数学错误: {e}")运行示例:
text
请输入一个数字: abc ❌ 类型错误: invalid literal for int() with base 10: 'abc'
🔄 四、else和finally
4.1else:没有异常时执行
python
try: num = int(input("请输入一个数字: ")) result = 10 / num except ValueError: print("❌ 请输入有效的数字") except ZeroDivisionError: print("❌ 不能除以零") else: print(f"✅ 计算结果: {result}") # 只有没有异常时才执行运行示例:
text
请输入一个数字: 5 ✅ 计算结果: 2.0
4.2finally:无论是否异常都执行
finally中的代码一定会执行,通常用来做清理工作(如关闭文件、释放资源)。
python
try: file = open("data.txt", "r") content = file.read() print(content) except FileNotFoundError: print("❌ 文件不存在") finally: print("清理资源...") # file.close() # 注意:如果文件没打开,这里会报错,需要用 with 代替💡 实际开发中,文件操作直接用
with语句更安全,不需要手动finally。
4.3 完整结构
python
try: # 可能出错的代码 except 异常类型1: # 处理异常1 except 异常类型2: # 处理异常2 else: # 没有异常时执行 finally: # 总是执行
🚀 五、主动抛出异常:raise
有时候我们希望主动触发一个异常,比如参数不符合要求时。
5.1 基本用法
python
def set_age(age): if age < 0 or age > 150: raise ValueError("年龄必须在 0-150 之间") print(f"年龄设置为: {age}") try: set_age(200) except ValueError as e: print(f"❌ 参数错误: {e}")运行结果:
text
❌ 参数错误: 年龄必须在 0-150 之间
5.2 重新抛出异常
有时候捕获异常后,只想记录日志,然后继续把异常往上抛。
python
def divide(a, b): try: return a / b except ZeroDivisionError: print("记录日志:除数不能为0") raise # 重新抛出同一个异常 try: divide(10, 0) except ZeroDivisionError: print("主程序捕获到异常")运行结果:
text
记录日志:除数不能为0 主程序捕获到异常
📋 六、常见异常类型一览
| 异常类型 | 触发条件 |
|---|---|
ZeroDivisionError | 除以零 |
ValueError | 传入的值类型正确但内容无效(如int("abc")) |
TypeError | 操作或函数应用于错误类型(如"10" + 5) |
IndexError | 序列索引超出范围 |
KeyError | 字典中访问不存在的键 |
FileNotFoundError | 文件不存在 |
NameError | 使用未定义的变量 |
AttributeError | 访问对象不存在的属性或方法 |
SyntaxError | 语法错误(编译时触发,不是运行时异常) |
💡 异常类型有继承关系,
Exception是所有异常的基类。捕获Exception可以捕获所有异常。
🧪 七、综合示例:安全的计算器
python
# 第11天综合示例:带异常处理的四则运算 def safe_divide(a, b): """安全的除法,处理除零异常""" try: return a / b except ZeroDivisionError: return "错误:除数不能为0" def safe_int_input(prompt): """安全地获取整数输入""" while True: try: value = int(input(prompt)) return value except ValueError: print("❌ 请输入有效的整数,请重试") def safe_float_input(prompt): """安全地获取浮点数输入""" while True: try: value = float(input(prompt)) return value except ValueError: print("❌ 请输入有效的数字,请重试") def calculator(): """主计算器程序""" print("=" * 40) print(" 安全计算器(带异常处理)") print("=" * 40) while True: try: num1 = safe_float_input("请输入第一个数字: ") op = input("请输入运算符(+ - * /): ") num2 = safe_float_input("请输入第二个数字: ") if op == "+": result = num1 + num2 elif op == "-": result = num1 - num2 elif op == "*": result = num1 * num2 elif op == "/": result = safe_divide(num1, num2) else: print("❌ 不支持的运算符") continue if isinstance(result, str): print(f"❌ {result}") else: print(f"✅ {num1} {op} {num2} = {result}") except Exception as e: print(f"❌ 发生意外错误: {e}") # 询问是否继续 again = input("\n继续计算?(y/n): ").lower() if again != 'y': print("👋 再见!") break if __name__ == "__main__": calculator()运行示例:
text
======================================== 安全计算器(带异常处理) ======================================== 请输入第一个数字: abc ❌ 请输入有效的数字,请重试 请输入第一个数字: 10 请输入运算符(+ - * /): / 请输入第二个数字: 0 ❌ 错误:除数不能为0 继续计算?(y/n): y 请输入第一个数字: 10 请输入运算符(+ - * /): + 请输入第二个数字: 5 ✅ 10.0 + 5.0 = 15.0 继续计算?(y/n): n 👋 再见!
🐛 八、新手常见错误及解决
| 错误现象 | 错误代码示例 | 解决方法 |
|---|---|---|
except没有捕获到异常 | except:但异常类型不匹配 | 用更宽泛的Exception或添加具体类型 |
| 捕获了但没做任何处理 | except: pass | 至少打印日志或提示用户 |
忘记except的冒号 | except ValueError(没有冒号) | 加冒号:except ValueError: |
finally里操作可能出错的资源 | finally: file.close()但文件没打开 | 用with代替手动管理 |
raise后没有重新处理 | raise后程序还是会崩溃 | 确保调用方有对应的try-except |
| 捕获了所有异常但掩盖了真实问题 | except: pass | 打印或记录异常信息便于调试 |
错误演示:捕获了异常但无法调试
python
try: num = int(input("输入数字: ")) print(10 / num) except: print("出错了") # 不知道具体是什么错改进:
python
try: num = int(input("输入数字: ")) print(10 / num) except Exception as e: print(f"出错了: {type(e).__name__} - {e}") # 打印异常类型和详细信息🎯 今日总结
今天你学会了:
什么是异常(程序运行时的错误)
try-except捕获异常的基本语法捕获特定类型的异常(
ValueError,ZeroDivisionError等)else(没有异常时执行)和finally(始终执行)主动抛出异常(
raise)常见异常类型
编写了带异常处理的安全计算器