异常处理——出问题了怎么办:给代码“装安全气囊” 🛡️

296次阅读

1. 代码的“意外”:异常是躲不开的 🤕

关键字:异常、程序崩溃、健壮性内容详解:
再完美的代码也会遇到“意外”——比如数据库突然连不上、用户输入了非法内容、文件被删了…如果不管这些“意外”,程序会直接崩溃(像汽车撞墙一样)。
异常处理 就是给代码“装安全气囊”:遇到问题时不崩溃,而是“优雅地处理”(比如提示错误、重试操作),让程序更 健壮(不容易挂掉)。
类比:你点外卖,万一商家没货(异常),APP 不会闪退,而是提示“商品售罄”并推荐替代品——这就是“异常处理”的思路!

2. 异常处理入门:try-except——“试试看,出问题就处理”🧪

关键字:try 语句、except 子句、异常捕获

内容详解:
Python 用 try-except 捕获异常,格式是:把“可能出问题的代码”放在 try 里,“出问题后怎么处理”放在 except 里。比如处理“除以 0”的错误:

def divide(a, b):
    try:
        # 可能出问题的代码:b 为 0 会报错
        return a / b
    except ZeroDivisionError:
        # 捕获“除以 0”异常,处理它
        print("错误:除数不能为 0!")
        return None  # 返回一个安全的结果

# 测试:正常情况
print(divide(4, 2))  # 输出 2.0
# 测试:异常情况
print(divide(4, 0))  # 输出“错误:除数不能为 0!”和 None

没有异常处理时,4/0会让程序崩溃;加了try-except,程序会提示错误并继续运行!

3. 灵活处理:捕获多种异常 +“兜底”处理 🎯

关键字:多 except 子句、Exception 基类、异常信息

内容详解:
一个 try 可以配多个except,捕获不同类型的异常;还能用Exception(所有异常的基类)“兜底”捕获未知异常:

def read_file(file_path):
    try:
        with open(file_path, "r") as f:
            return f.read()
    except FileNotFoundError:
        # 捕获“文件不存在”异常
        print(f"错误:文件 {file_path} 不存在!")
        return ""
    except PermissionError:
        # 捕获“权限不足”异常
        print(f"错误:没有读取 {file_path} 的权限!")
        return ""
    except Exception as e:
        # 兜底:捕获其他所有异常,e 是异常对象(包含错误信息)print(f"未知错误:{e}")
        return ""

# 测试不同异常
read_file("不存在的文件.txt")  # 提示“文件不存在”read_file("/root/ 敏感文件.txt")  # 提示“权限不足”read_file(123)  # 提示“未知错误:expected str, bytes or os.PathLike object, not int”

这样不管遇到哪种错误,程序都能“温柔地”给出提示,而不是直接崩溃~

4. Web 场景:给数据库操作加“异常防护”🕸️

关键字:Flask 异常处理、数据库异常、重试机制

内容详解:
Web 应用中,数据库连接失败是常见异常——用 try-except 给数据库操作加防护,甚至加“重试”功能:

from flask import Flask
import mysql.connector
import time

app = Flask(__name__)

def get_db_data(retry=3):
    while retry > 0:
        try:
            # 尝试连接数据库
            conn = mysql.connector.connect(host="localhost", user="root", password="你的密码", database="web_log_db")
            cursor = conn.cursor()
            cursor.execute("SELECT COUNT(*) FROM access_log")
            result = cursor.fetchone()[0]
            conn.close()
            return result
        except mysql.connector.Error as e:
            # 捕获数据库异常
            print(f"数据库错误:{e},剩余重试次数{retry-1}")
            retry -= 1
            time.sleep(1)  # 等 1 秒再重试
    # 重试失败,返回默认值
    return "数据库连接失败"

@app.route("/log_count")
def log_count():
    count = get_db_data()
    return f"总访问次数:{count}"

if __name__ == "__main__":
    app.run(debug=True)

现在如果数据库临时断开,程序会重试 3 次;都失败了也会返回“数据库连接失败”,而不是让 Web 应用崩溃——用户体验会好很多!

5. 高阶技巧:自定义异常 +finally“收尾”🧩

关键字:自定义异常、raise 语句、finally 子句

内容详解:
除了 Python 自带的异常,你还能 自定义异常 (处理业务相关的错误);finally 子句 则能保证“不管有没有异常,都执行收尾操作”:

# 自定义异常:业务相关的错误
class InvalidUserError(Exception):
    def __init__(self, user_id):
        self.user_id = user_id
        self.message = f"用户 {user_id} 不存在"
        super().__init__(self.message)

def get_user_info(user_id):
    # 模拟查询用户,不存在则抛自定义异常
    users = {"1": "张三", "2": "李四"}
    if user_id not in users:
        raise InvalidUserError(user_id)  # 主动抛异常
    return users[user_id]

def process_user(user_id):
    conn = None
    try:
        user = get_user_info(user_id)
        # 模拟数据库操作
        conn = mysql.connector.connect(...)
        print(f"处理用户{user}")
    except InvalidUserError as e:
        # 捕获自定义异常
        print(f"业务错误:{e.message}")
    except Exception as e:
        print(f"系统错误:{e}")
    finally:
        # 不管有没有异常,都关闭数据库连接
        if conn:
            conn.close()
            print("数据库连接已关闭")

# 测试:正常用户
process_user("1")  # 输出“处理用户张三”和“数据库连接已关闭”# 测试:不存在的用户
process_user("3")  # 输出“业务错误:用户 3 不存在”和“数据库连接已关闭”

自定义异常让“业务错误”和“系统错误”分开处理;finally则保证资源(比如数据库连接)一定会被清理!

6. 避坑指南:异常处理的“红线”🚫

关键字:异常吞没、日志记录、合理捕获

内容详解:
异常处理要避免一个常见错误:吞没异常 (只写except: 却不处理 / 记录错误)——比如:

# 错误示例:吞没异常,出问题了都不知道
try:
    4 / 0
except:
    pass  # 啥也不做

正确的做法是:

  • ✅ 只捕获“你能处理的异常”,未知异常交给上层处理;
  • ✅ 记录异常信息(比如用 print 或日志模块),方便排查问题;
  • ✅ 不要用异常处理“代替正常的条件判断”(比如用 try 判断用户输入是否为数字,不如直接用isdigit())。

记住:异常处理是“应对意外”,不是“掩盖错误”!

正文完
 0