Python 的 try 语句(异常处理)详细介绍

Python 的 try 语句(异常处理)详细介绍

在 Python 中,try语句是异常处理(Error Handling) 的核心机制,用于捕获和处理程序运行过程中出现的错误(如语法错误之外的运行时错误:除零错误、索引越界、网络请求失败等),避免程序因错误直接崩溃,让程序具备更强的鲁棒性。(在编程领域,鲁棒性(Robustness) 指的是程序在面对异常、错误、非法输入或恶劣环境时,能够保持稳定运行而不崩溃,并且能合理处理这些异常情况的能力。简单来说,就是程序的 “抗造”“耐折腾” 程度。

一、异常的基本概念

异常是程序运行时发生的不正常情况(错误),比如:

ZeroDivisionError:除数为 0;IndexError:列表索引超出范围;KeyError:字典键不存在;requests.exceptions.RequestException:网络请求失败(如超时、连接拒绝);FileNotFoundError:文件不存在。

如果不处理这些异常,程序会直接终止并抛出错误信息;而try语句可以捕获这些异常,并执行自定义的处理逻辑。

二、try 语句的完整语法结构

Python 的try语句有多种组合形式,从简单到复杂依次为:try-excepttry-except-elsetry-except-finallytry-except-else-finally

1. 基础结构:try-except(核心)

这是最常用的形式,用于捕获并处理指定的异常

try: # 可能引发异常的代码块(受保护的代码) risky_code() except [异常类型1] [as 异常对象]: # 当异常类型1发生时,执行的处理逻辑 handle_exception1() except [异常类型2] [as 异常对象]: # 当异常类型2发生时,执行的处理逻辑 handle_exception2() except: # 捕获所有未被上面捕获的异常(兜底处理,不推荐滥用) handle_all_other_exceptions() 

关键说明

try块:存放可能出现异常的代码(如网络请求、文件操作、数据类型转换等)。except块:当try块中发生指定类型的异常时,执行该块的代码;可以有多个except块,分别处理不同类型的异常。as 异常对象:可选,用于获取异常的详细信息(如错误描述、堆栈信息),常用变量名:eerr

示例 1:捕获特定异常

try: a = 10 / 0 # 会引发ZeroDivisionError b = [1, 2, 3][5] # 会引发IndexError(但上面的错误先发生,这行不会执行) except ZeroDivisionError as e: print(f"错误:除数不能为0,异常信息:{e}") except IndexError as e: print(f"错误:索引越界,异常信息:{e}") 

输出:错误:除数不能为0,异常信息:division by zero

示例 2:捕获多个异常(简写)如果多个异常的处理逻辑相同,可以将它们放在一个except块中,用元组包裹:

try: data = {"name": "张三"} print(data["age"]) # KeyError # num = int("abc") # ValueError except (KeyError, ValueError) as e: print(f"发生了键错误或值错误:{e}") 

示例 3:兜底捕获所有异常(不推荐)使用无参数的except可以捕获所有异常,但会隐藏未知的错误,不利于调试,仅建议在程序顶层做兜底处理:

try: 10 / 0 except ZeroDivisionError as e: print(f"除数为0:{e}") except: print(f"发生了未知错误:{e}") # 兜底处理 
2. 扩展结构:try-except-else

try块中没有发生任何异常时,会执行else块的代码(else块是可选的)。

try: # 可能引发异常的代码 result = 10 / 2 except ZeroDivisionError as e: print(f"错误:{e}") else: # 无异常时执行的代码 print(f"计算结果:{result}") 

输出:计算结果:5.0

作用将 “正常逻辑” 和 “异常处理逻辑” 分离,代码结构更清晰(else块只执行正常情况的逻辑)。

仅当try块中的代码:正常执行完毕(没有引发任何异常);且没有被returnbreakcontinue等语句中断;才会执行else块的代码。如果try块中引发了异常:程序会立即跳转到对应的except块中执行异常处理逻辑;else块的代码会被完全跳过,不会执行。
3. 完整结构:try-except-finally

finally块中的代码无论是否发生异常,都会执行finally块是可选的),常用于释放资源(如关闭文件、关闭网络连接、释放锁等)。

try: # 可能引发异常的代码 f = open("test.txt", "r") content = f.read() except FileNotFoundError as e: print(f"错误:文件不存在,{e}") finally: # 无论是否异常,都会执行:关闭文件 if 'f' in locals() and not f.closed: f.close() print("文件已关闭") 

关键特性

即使try块中有returnbreakcontinue等语句,finally块仍会执行;常用于资源的清理工作,避免资源泄漏。
4. 终极结构:try-except-else-finally

整合所有部分,覆盖所有场景:

try: num = int(input("请输入一个整数:")) result = 10 / num except ValueError as e: print(f"错误:请输入有效的整数,{e}") except ZeroDivisionError as e: print(f"错误:除数不能为0,{e}") else: print(f"10 / {num} = {result}") finally: print("程序执行完毕(无论是否异常,都会显示)") 

三、异常对象的常用操作

通过as 异常对象可以获取异常的详细信息,常用操作:

直接打印异常对象:获取错误描述(如print(e));获取异常类型type(e)获取异常的堆栈信息:使用traceback模块(适合调试)。
import traceback try: 10 / 0 except Exception as e: # 打印错误描述 print(f"异常描述:{e}") # 打印异常类型 print(f"异常类型:{type(e)}") # 打印完整的堆栈信息(包含出错的行号、文件路径) print("堆栈信息:") traceback.print_exc() 

五、try 语句的使用场景(爬虫 / 开发常用)

1. 网络请求(处理网络异常)

爬虫中网络请求容易出现超时、连接拒绝、DNS 错误等异常,必须用try处理:

import requests HEADERS = {"User-Agent": "Mozilla/5.0"} url = "https://movie.douban.com/top250" try: response = requests.get(url, headers=HEADERS, timeout=10) response.raise_for_status() # 触发HTTP错误(如403、404、500) except requests.exceptions.Timeout as e: print(f"错误:请求超时,{e}") except requests.exceptions.HTTPError as e: print(f"错误:HTTP状态码异常,{e}") except requests.exceptions.RequestException as e: print(f"错误:网络请求失败,{e}") else: print(f"请求成功,状态码:{response.status_code}") 
2. 文件操作(处理文件不存在、权限错误)
try: with open("douban_top50.csv", "r", encoding="utf-8-sig") as f: content = f.read() except FileNotFoundError as e: print(f"错误:文件不存在,{e}") except PermissionError as e: print(f"错误:没有文件读取权限,{e}") except UnicodeDecodeError as e: print(f"错误:文件编码错误,{e}") else: print(f"文件读取成功,内容长度:{len(content)}") 
3. 数据解析(处理数据格式异常)

爬虫解析数据时,可能因网页结构变化导致标签不存在,需处理异常:

from bs4 import BeautifulSoup html = '<div><span>肖申克的救赎</span></div>' soup = BeautifulSoup(html, "html.parser") try: movie_name = soup.find("span", class_="title").text movie_score = soup.find("span", class_="rating_num").text # 该标签不存在,触发AttributeError except AttributeError as e: print(f"错误:标签不存在,{e}") movie_score = "未知" finally: print(f"电影名称:{movie_name},评分:{movie_score}") 

输出:错误:标签不存在,'NoneType' object has no attribute 'text'电影名称:肖申克的救赎,评分:未知

六、使用 try 的最佳实践

精准捕获异常:尽量捕获具体的异常类型(如ZeroDivisionError),避免使用无参数的except(兜底除外),否则会隐藏未知错误;保持 try 块最小化:只在try块中放入可能引发异常的代码,不要将无关代码放入,便于定位错误;使用 finally 释放资源:对于文件、网络连接、数据库连接等资源,务必在finally中释放,或使用上下文管理器(with语句,底层也是基于finally实现);异常信息要明确:处理异常时,打印清晰的错误信息(如异常类型、错误原因、发生位置),便于调试;避免过度使用异常:异常处理是为了处理不可预见的错误,不要用异常处理替代正常的逻辑判断(如不要用try-except判断列表是否为空,应直接用if not lst)。

七、与上下文管理器(with 语句)的结合

Python 中的with语句是异常处理的语法糖,常用于资源管理(如文件、网络连接),它会自动在代码块结束后释放资源,即使发生异常也不例外(底层调用了__enter____exit__方法,__exit__中包含了finally的逻辑)。

示例:用 with 语句简化文件操作(替代 try-finally)

# 无需手动关闭文件,with语句会自动处理 try: with open("test.txt", "r") as f: content = f.read() except FileNotFoundError as e: print(f"错误:文件不存在,{e}") else: print(f"文件内容:{content}") 

总结

        Python 的try语句是处理运行时异常的核心工具,通过try-except捕获异常、else执行正常逻辑、finally释放资源,能让程序在面对错误时更健壮。在爬虫、文件操作、数据处理等场景中,合理使用try语句是编写生产级代码的必备技能。同时,遵循精准捕获、最小化 try 块、明确异常信息等最佳实践,能让异常处理代码更优雅、更易维护。

Read more

华为OD技术面八股文_C++_01

华为OD技术面八股文_C++_01

文章目录 * C语言和C++的区别 * C++11引入哪些新特性 * 什么是面向对象?面向对象的三大特性 * malloc和new的区别 * delete和free的区别 * delete和delete[]的区别 * 什么是虚函数?什么是纯虚函数 * 什么是虚函数表?什么是虚函数指针? * 介绍一下虚函数实现机制 * 构造函数和构析函数能不能写为虚函数,为什么 * 说一下构造、析构函数的调用顺序 C语言和C++的区别 1. C++有新增的关键字和语法,还允许自定义命名空间。 2. C++新增类的概念,C语言中只有struct的概念。C++中添加访问权限概念,struct 的默认访问权限和继承权限都是 public,但是 class 的默认访问权限和默认继承权限都是 private. 3. C++引入了类、封装、继承、多态、模板、重载、异常处理机制等特性。而C没有 4.

By Ne0inhk
C++可变参数队列与压栈顺序:从模板语法到汇编调用约定的深度解析

C++可变参数队列与压栈顺序:从模板语法到汇编调用约定的深度解析

C++可变参数队列与压栈顺序:从模板语法到汇编调用约定的深度解析 本文聚焦一个具体而关键的技术主题:C++ 可变参数模板(Variadic Templates)。我们将从现代 C++ 的优雅写法出发,深入剖析其在 x86-64 架构下的真实行为,特别澄清一个长期被误解的核心问题——可变参数是否“从右向左压栈”?它们在寄存器和栈中究竟是如何排布的? 如果你正在实现一个类型安全的消息队列、日志系统或任务调度器,并希望理解 enqueue(1, "hello", 3.14) 这行代码在 CPU 层面到底发生了什么,那么这篇文章就是为你量身打造的。 一、引言:可变参数 ≠ va_list —— 一场范式革命 很多初学者将 C++ 的可变参数模板与 C 语言的 va_list 混为一谈。这是重大误区,甚至会导致错误的性能假设和安全漏洞。 1.1

By Ne0inhk
《C++ Stack 与 Queue 完全使用指南:基础操作 + 经典场景 + 实战习题》

《C++ Stack 与 Queue 完全使用指南:基础操作 + 经典场景 + 实战习题》

🔥草莓熊Lotso:个人主页 ❄️个人专栏: 《C++知识分享》《Linux 入门到实践:零基础也能懂》 ✨生活是默默的坚持,毅力是永久的享受! 🎬 博主简介: 文章目录 * 前言: * 一. 先搞懂基础:Stack 与 Queue 的核心特性 * 二. Stack(栈):后进先出(LIFO)的容器 * 2.1 核心特性: * 2.2 头文件与定义 * 2.3 常用接口全解析 * 2.4 基础用法演示 * 三. Queue(队列):先进先出(FIFO)的容器 * 3.1 核心特性: * 3.2 头文件与定义: * 3.

By Ne0inhk
【C++】第十七节—二叉搜索树(概念+性能分析+增删查+实现+使用场景)

【C++】第十七节—二叉搜索树(概念+性能分析+增删查+实现+使用场景)

好久不见,我是云边有个稻草人 《C++》本文所属专栏—持续更新中—欢迎订阅 目录 一、二叉搜索树的概念 二、二叉搜索树的性能分析 三、二叉搜索树的插入 SearchBinaryTree.h test.cpp 四、⼆叉搜索树的查找 【只有一个3】 【有多个3】  五、⼆叉搜索树的删除 六、二叉搜索树的实现代码 SearchBinaryTree.h test.cpp  七、二叉搜索树key和key/value使用场景 7.1 key搜索场景 7.2 key/value搜索场景 7.3 key/value⼆叉搜索树代码实现 .h .cpp 正文开始—— 一、二叉搜索树的概念 ⼆叉搜索树⼜

By Ne0inhk