为什么需要异常
age = int(input("年龄: ")) # 用户输入 "abc" → ValueError,程序崩
异常处理的目的:预测可能出错的地方,给出合理的应对。
基本结构
try:
age = int(input("年龄: "))
print(f"明年 {age + 1} 岁")
except ValueError:
print("请输入数字")
多个 except
try:
n = int(input("分母: "))
print(10 / n)
except ValueError:
print("不是数字")
except ZeroDivisionError:
print("不能除以 0")
except Exception as e: # 兜底
print(f"其他错误: {e}")
顺序:具体的异常在前,宽泛的(Exception)在最后。
一个 except 抓多种
try:
...
except (ValueError, TypeError) as e:
print(f"类型相关错误: {e}")
else:没出错才执行
try:
n = int(input("数字: "))
except ValueError:
print("失败")
else:
print(f"成功,值是 {n}") # 仅在没异常时走
finally:不管出不出错都执行
try:
f = open("data.txt")
...
except FileNotFoundError:
print("找不到文件")
finally:
print("清理工作") # 永远执行
文件清理用
with更优雅——不需要写 finally。
主动抛异常
def divide(a, b):
if b == 0:
raise ValueError("分母不能为 0")
return a / b
用 raise 主动抛异常——比返回 None 更明确。
自定义异常
class NotFoundError(Exception):
pass
def find_user(uid):
if uid not in db:
raise NotFoundError(f"用户 {uid} 不存在")
return db[uid]
反模式:吞掉所有异常
# 别这样写
try:
do_something()
except:
pass # 出了任何错都假装没事——bug 永远找不到
至少打印日志,至少记下异常类型。
实战:安全转换数字
def to_int(s, default=0):
try:
return int(s)
except (ValueError, TypeError):
return default
to_int("42") # 42
to_int("abc") # 0
to_int(None) # 0
下一篇讲模块与 import——把代码拆到多个文件。