Python
基础语法
01概念
02安装
03变量
04字符串
05数
06常量与注释
07列表
08元组
09if语句
10字典
11集合
12复合数据类型对比
13推导式
14用户输入
15while循环
16函数
17类
18面向对象编程
19文件操作
20异常处理
21日期和时间
22魔术方法
23内置函数
24线程
25并发&并行
26正则表达式
27迭代器
28装饰器
29生成器
30上下文管理器
31函数式编程
32闭包
33解包
34工具库
35连接关系型数据库
36虚拟环境
37异步编程
网络爬虫
01urllib库[了解]
02requests库
03数据交换格式
04解析库
05lxml
06Beautiful Soup
07Xpath语法
08动态网页的处理
-
+
首页
20异常处理
在 Python 中,**异常处理(Exception Handling)** 是一种机制,用于捕获和处理程序执行过程中出现的**异常(错误)**,避免程序因未处理的错误而直接崩溃,同时提供错误信息以便调试或友好提示用户。 ## 概述 异常是程序执行时发生的**意外错误事件**(如除数为 0、访问不存在的文件、类型不匹配等)。当异常发生且未被处理时,Python 会终止程序并打印错误信息(** traceback **),例如: ```python # 未处理的异常:除数为0 >>> print(1 / 0) # 触发ZeroDivisionError,程序崩溃 Traceback (most recent call last): File "<python-input-0>", line 1, in <module> print(1 / 0) ~~^~~ ZeroDivisionError: division by zero ``` ## 常见内置异常类型 Python 定义了多种内置异常,对应不同的错误场景,常见类型如下: | 异常类型 | 触发场景 | 示例 | | ----------------- | --------------------------------- | ---------------------------------- | | SyntaxError | 代码语法错误(Python 解析时发现) | print("缺少右括号") | | NameError | 使用未定义的变量 | print(undefined_var) | | TypeError | 操作或函数应用于不适当类型的对象 | "2" + 2(字符串与整数拼接) | | ValueError | 函数接收到的参数值有效但不合适 | int("abc")(字符串无法转为整数) | | IndexError | 序列索引超出范围 | \[1,2,3][5] | | KeyError | 访问字典中不存在的键 | {"name": "Tom"}["age"] | | FileNotFoundError | 尝试打开不存在的文件 | open("nonexistent.txt") | | PermissionError | 没有操作文件 / 目录的权限 | open("/root/secret.txt")(无权限) | | ZeroDivisionError | 除数为 0 | 10 / 0 | 所有内置异常均继承自基类Exception,可通过help(Exception)查看完整层级。 ```python >>> help(Exception) Help on class Exception in module builtins: class Exception(BaseException) | Common base class for all non-exit exceptions. | | Method resolution order: | Exception | BaseException | object | | Built-in subclasses: | ArithmeticError | AssertionError | AttributeError | BufferError | ... and 16 other subclasses | | Methods defined here: | | __init__(self, /, *args, **kwargs) | Initialize self. See help(type(self)) for accurate signature. | | ---------------------------------------------------------------------- | Static methods defined here: | | __new__(*args, **kwargs) | Create and return a new object. See help(type) for accurate signature. | | ---------------------------------------------------------------------- | Methods inherited from BaseException: | | __getattribute__(self, name, /) | Return getattr(self, name). | | __reduce__(self, /) | Helper for pickle. | | __repr__(self, /) | Return repr(self). | | __setstate__(self, object, /) | | __str__(self, /) | Return str(self). | | add_note(self, object, /) -- More -- ``` ## 语法 Python 通过try-except-else-finally语句结构处理异常,各部分分工明确: ```python try: # 可能触发异常的代码块(核心逻辑) risky_operation() except 异常类型1 as 变量名: # 捕获并处理“异常类型1”的逻辑 handle_error1(变量名) except (异常类型2, 异常类型3) as 变量名: # 同时捕获多种异常的逻辑 handle_errors23(变量名) else: # 可选:当try块无异常时执行(仅在无异常时) success_operation() finally: # 可选:无论是否有异常,最终都会执行(用于资源清理) cleanup_resources() ``` ### try try块包含**可能触发异常的核心逻辑**(如文件操作、网络请求、数据转换等)。Python 会监控该块中的代码: - 若执行中触发异常,立即终止try块,跳转到对应的except块处理; - 若未触发异常,try块执行完毕后,继续执行else块(若有),最后执行finally块(若有)。 ### except except块用于**捕获特定类型的异常**并执行处理逻辑,核心要点: - **捕获特定异常**:except 异常类型仅处理指定类型的异常,例如except FileNotFoundError专门处理文件不存在的错误。 ```python try: open("test.txt") except FileNotFoundError: print("错误:文件不存在") # 仅当文件不存在时执行 ``` **捕获多种异常**:通过元组(异常1, 异常2)同时捕获多种异常,适用于多种错误可统一处理的场景。 ```python try: num = int(input("请输入数字:")) print(10 / num) except (ValueError, ZeroDivisionError): print("错误:输入必须是非零数字") # 处理输入非数字或除数为0的情况 ``` **获取异常信息**:通过as 变量名绑定异常对象,可获取错误详情(如错误消息)。 ```python >>> try: ... 1 / 0 ... except ZeroDivisionError as e: ... print(f"发生错误:{e}") ... #输出信息: 发生错误:division by zero ``` **捕获所有异常**:except Exception可捕获所有非系统退出类异常(不推荐滥用,可能掩盖逻辑错误)。 ```python try: risky_code() except Exception as e: print(f"发生未知错误:{e}") # 捕获所有继承自Exception的异常 ``` ### else else块是**可选的**,仅当try块**未触发任何异常**时执行,用于处理正常流程的后续逻辑,避免将成功逻辑混入try块(提高可读性)。 ```python try: num = int(input("请输入数字:")) except ValueError: print("输入不是有效数字") else: # 仅当输入是有效数字时执行 print(f"你输入的数字是:{num}") ``` 执行两次,输出结果: ```python #第一次 请输入数字:10 你输入的数字是:10 #第二次 请输入数字:g 输入不是有效数字 ``` ### finally finally块是**可选的**,无论try块是否触发异常(甚至try/except/else中出现return),**一定会执行**,主要用于释放资源(如关闭文件、断开连接)。 ```python file = None try: file = open("test.txt", "r") content = file.read() except FileNotFoundError: print("文件不存在") finally: # 无论是否出错,确保文件关闭 if file: file.close() print("文件已关闭") ``` 注意:with语句(上下文管理器)可替代finally实现自动资源释放,但finally更通用(如释放锁、清理临时文件等)。 ## 主动抛出异常 在 Python 中,**主动抛出异常**是指开发者通过raise语句**手动触发异常**,而非等待程序执行时自动产生错误。 这种机制的核心价值是:当业务逻辑不符合预期(如参数无效、权限不足等)时,主动中断程序流程并传递明确的错误信息,让调用者(或上层代码)知晓问题所在并进行处理。 **1. 抛出指定类型的异常(带默认消息)** 语法:raise 异常类型,直接抛出内置或自定义异常类型,使用该异常的默认错误消息。 ```python def check_positive(num): if num <= 0: # 当数字非正数时,主动抛出ValueError(内置异常) raise ValueError # 抛出异常,使用默认消息 check_positive(-5) # 输出: ValueError (触发异常,程序中断) ``` **2. 抛出异常并自定义错误消息** 语法:raise 异常类型(错误消息),抛出异常时,通过括号传入自定义字符串作为错误消息,让错误原因更明确。 ```python def check_positive(num): if num <= 0: # 自定义错误消息,说明具体问题 raise ValueError(f"输入的数字{num}必须是正数") check_positive(-5) # 输出: ValueError: 输入的数字-5必须是正数 (错误消息更清晰) ``` **3. 重新抛出异常(不改变原始异常)** 语法:raise(无参数),在except块中捕获异常后,若无法完全处理,可通过raise(不带参数)将异常原样传递给上层代码,保留原始异常的类型和消息。 ```python def read_file(filename): try: with open(filename, "r") as f: return f.read() except FileNotFoundError as e: # 处理部分逻辑(如记录日志),再将异常传递给上层 print(f"日志:尝试读取{filename}失败") raise # 重新抛出原始异常,不改变其信息 # 上层调用者处理重新抛出的异常 try: read_file("nonexist.txt") except FileNotFoundError as e: print(f"用户提示:文件不存在 - {e}") # 输出: 日志:尝试读取nonexist.txt失败 用户提示:文件不存在 - [Errno 2] No such file or directory: 'nonexist.txt' ``` 主动抛出异常不是 “制造错误”,而是**在业务规则被违反时,通过异常机制明确反馈问题**。常见场景包括: 参数合法性校验:当函数 / 方法的输入参数不符合预期(如类型错误、范围错误)时,主动抛出异常,避免错误的参数导致后续逻辑混乱。 ```python def calculate_bmi(weight, height): # 校验体重(必须>0) if weight <= 0: raise ValueError(f"体重{weight}无效,必须大于0") # 校验身高(必须>0且合理) if height <= 0 or height > 3: raise ValueError(f"身高{height}无效,必须在(0, 3]米范围内") return weight / (height **2) # 测试无效参数 try: calculate_bmi(-50, 1.75) except ValueError as e: print(f"计算失败:{e}") # 输出:计算失败:体重-50无效,必须大于0 ``` 业务规则校验:在特定业务场景中,当操作违反预设规则(如权限不足、状态错误)时,主动抛出异常,确保业务逻辑的正确性。 ```python class Order: def __init__(self, status="pending"): self.status = status # 订单状态:pending(待支付)、paid(已支付)、cancelled(已取消) def pay(self): if self.status != "pending": # 只有待支付状态可付款,否则抛出异常 raise RuntimeError(f"订单当前状态为{self.status},无法支付(仅待支付订单可付款)") self.status = "paid" print("订单支付成功") # 测试业务规则 order = Order(status="paid") # 已支付订单 try: order.pay() except RuntimeError as e: print(f"操作失败:{e}") # 输出:操作失败:订单当前状态为paid,无法支付(仅待支付订单可付款) ``` 封装底层异常(提供更友好的上层接口):当调用底层库(如数据库、网络接口)时,底层可能抛出晦涩的异常(如psycopg2.OperationalError),可捕获后转换为自定义异常,向上层提供更易理解的错误信息。 ```python # 模拟底层数据库异常 class DatabaseError(Exception): pass # 底层库的异常 # 自定义上层业务异常 class DataAccessError(Exception): """数据访问异常(对上层友好)""" pass def get_user(user_id): try: # 模拟调用底层数据库,可能抛出底层异常 if user_id <= 0: raise DatabaseError("Invalid user_id (must be positive)") # 底层晦涩异常 return {"id": user_id, "name": "Alice"} except DatabaseError as e: # 将底层异常转换为上层友好的自定义异常 raise DataAccessError(f"获取用户{user_id}失败:{e}") from e # from e保留原始异常链 # 上层调用 try: get_user(-1) except DataAccessError as e: print(f"用户提示:{e}") # 输出:用户提示:获取用户-1失败:Invalid user_id (must be positive) ``` ## 自定义异常 当内置异常无法满足业务需求时,可通过**继承Exception类**定义自定义异常,使错误信息更具针对性(如 “用户年龄必须大于 0”)。 **定义自定义异常** ```python # 自定义异常:继承自Exception class InvalidAgeError(Exception): """当年龄无效时触发的异常""" # 可自定义初始化方法,添加额外信息 def __init__(self, age, message="年龄必须大于0且小于150"): self.age = age self.message = message super().__init__(self.message) # 调用父类构造方法 ``` **使用自定义异常** ```python def set_age(age): if not (0 < age < 150): # 抛出自定义异常 raise InvalidAgeError(age) print(f"年龄设置为:{age}") try: set_age(200) except InvalidAgeError as e: # 处理自定义异常 print(f"错误:{e.message},输入的年龄是{e.age}") # 输出:错误:年龄必须大于0且小于150,输入的年龄是200 ``` 输出结果 ```python 错误:年龄必须大于0且小于150,输入的年龄是200 ``` ## 总结 异常处理是 Python 程序健壮性的核心保障,其核心价值在于: - **阻止程序崩溃**:捕获异常后,程序可继续执行后续逻辑; - **明确错误原因**:通过异常对象获取错误详情,便于调试; - **友好交互**:向用户展示易懂的错误提示(而非技术 traceback); - **资源安全**:通过finally确保资源释放,避免泄漏。
毛林
2025年9月7日 11:45
转发文档
收藏文档
上一篇
下一篇
手机扫码
复制链接
手机扫一扫转发分享
复制链接
Markdown文件
PDF文档(打印)
分享
链接
类型
密码
更新密码