Python 写代码时,错误是常有的事。为了让程序更健壮,我们需要学会如何处理这些错误。这篇文章会带你从零开始了解 Python 的错误处理。


参考文章:


  1. 什么是异常?
  2. 常见的 Python 异常类型
  3. 基本的 try-except 结构
  4. 捕获特定异常
  5. 使用 else 和 finally
  6. 抛出异常
  7. 自定义异常
  8. 错误处理的最佳实践

1. 什么是异常?

异常(Exception)就是程序运行时发生的错误,比如试图打开一个不存在的文件、除以零或者输入了非法数据。Python 会抛出异常来告诉你“嘿,这里出问题了!”。如果不处理,程序会直接崩溃,打印一堆错误信息(就是 traceback)。

异常处理的核心是用代码“捕获”这些错误,防止程序崩掉,还能给用户友好的提示。

2. 常见的 Python 异常类型

Python 内置了很多异常类型,了解它们能帮你更好地处理问题。以下是一些常见的异常:

  • ZeroDivisionError:除以零时触发。
  • FileNotFoundError:试图打开不存在的文件。
  • ValueError:函数接收到不合适的参数,比如把字符串传给 int()
  • TypeError:类型错误,比如试图把字符串和整数相加。
  • IndexError:列表索引超出范围。
  • KeyError:访问字典中不存在的键。

这些异常都是 Python 的内置类,继承自 Exception 类。你可以在代码中捕获它们。

3. 基本的 try-except 结构

Python 用 try-except 块来处理异常。基本思路是:把可能出错的代码放进 try 块,如果出错了,就跳到 except 块执行。

来看个简单的例子:

try:
num = int(input("请输入一个数字: "))
result = 10 / num
print(f"10 除以 {num} 等于 {result}")
except:
print("出错了!可能输入了非法数字或除以零。")

运行这段代码:

  • 如果用户输入一个合法数字,比如 5,程序会打印 10 除以 5 等于 2.0
  • 如果输入了非数字(比如 "abc")或 0,程序会跳到 except 块,打印错误提示,而不会崩溃。

这个 except 是个“通吃”模式,捕获所有异常。但最好别这样用,因为你不知道具体出了啥问题。接下来我们改进它。

4. 捕获特定异常

与其捕获所有异常,不如只捕获你关心的特定异常类型。这样能更精准地处理问题。Python 允许在 except 后指定异常类型。

改写上面的例子:

try:
num = int(input("请输入一个数字: "))
result = 10 / num
print(f"10 除以 {num} 等于 {result}")
except ValueError:
print("请输入一个合法的数字!")
except ZeroDivisionError:
print("不能除以零!")

现在:

  • 如果输入 "abc",会触发 ValueError,打印“请输入一个合法的数字!”。
  • 如果输入 0,会触发 ZeroDivisionError,打印“不能除以零!”。
  • 其他异常(比如 KeyboardInterrupt)不会被捕获,程序会照常报错。

你可以捕获多个异常,也可以把异常对象保存下来,查看具体错误信息:

try:
num = int(input("请输入一个数字: "))
result = 10 / num
except ValueError as e:
print(f"输入错误: {e}")
except ZeroDivisionError as e:
print(f"除零错误: {e}")

这里 as e 把异常对象存到变量 e,可以打印更详细的错误信息。

5. 使用 else 和 finally

try-except 还有两个好用的伙伴:elsefinally

  • else:如果 try 块没出错,就执行 else 块。适合放那些依赖 try 块成功的代码。
  • finally:不管 try 块有没有出错,finally 块都会执行。常用来做清理工作,比如关闭文件。

来看个例子:

try:
num = int(input("请输入一个数字: "))
result = 10 / num
except ValueError:
print("请输入合法数字!")
except ZeroDivisionError:
print("不能除以零!")
else:
print(f"计算成功!结果是: {result}")
finally:
print("程序结束,清理完成!")

运行效果:

  • 输入 5:打印“计算成功!结果是: 2.0”和“程序结束,清理完成!”。
  • 输入 "abc":打印“请输入合法数字!”和“程序结束,清理完成!”。
  • 输入 0:打印“不能除以零!”和“程序结束,清理完成!”。

finally 特别适合确保资源被正确释放,比如:

try:
file = open("data.txt", "r")
content = file.read()
except FileNotFoundError:
print("文件没找到!")
else:
print(f"文件内容: {content}")
finally:
try:
file.close()
print("文件已关闭")
except NameError:
print("文件从未打开,无需关闭")

这里 finally 确保文件被关闭,即使文件没找到(导致 file 未定义)也能安全处理。

6. 抛出异常

有时候你想主动抛出异常,比如检查到用户输入不符合要求。可以用 raise 关键字抛出异常。

例子:

def divide(a, b):
if b == 0:
raise ZeroDivisionError("除数不能为零!")
return a / b try:
result = divide(10, 0)
except ZeroDivisionError as e:
print(f"错误: {e}")

运行会打印“错误: 除数不能为零!”。你可以用 raise 抛出任何内置异常,或者直接用 raise Exception("自定义消息")

还可以“重新抛出”异常:

try:
num = int(input("请输入一个数字: "))
except ValueError as e:
print(f"输入错误: {e}")
raise # 重新抛出原异常

这样会在处理完错误后,继续把异常抛给上层调用者。

7. 自定义异常

当内置异常不够用时,你可以定义自己的异常类。自定义异常通常继承自 Exception 类。

例子:

class CustomValueError(Exception):
"""自定义异常,用于值不符合要求"""
pass def check_age(age):
if age < 0 or age > 150:
raise CustomValueError("年龄必须在0到150之间!")
return age try:
age = check_age(200)
except CustomValueError as e:
print(f"错误: {e}")

运行会打印“错误: 年龄必须在0到150之间!”。自定义异常让代码更清晰,尤其在复杂项目中。

8. 错误处理的最佳实践

最后,分享一些写错误处理代码的建议:

  1. 捕获特定异常:别用“通吃”的 except,尽量指定具体的异常类型。
  2. 提供清晰的错误信息:用户看到错误时,应该知道问题出在哪,怎么解决。
  3. 用 else 和 finally 合理组织代码else 放依赖 try 成功的逻辑,finally 放清理工作。
  4. 别滥用异常:异常是用来处理“异常情况”的,别用它来控制正常流程(比如代替 if 判断)。
  5. 记录错误日志:在实际项目中,用 logging 模块记录异常,方便调试。

例子(带日志):

import logging

logging.basicConfig(level=logging.ERROR, filename="app.log")

try:
num = int(input("请输入一个数字: "))
result = 10 / num
except ValueError as e:
logging.error(f"输入错误: {e}")
print("请输入合法数字!")
except ZeroDivisionError as e:
logging.error(f"除零错误: {e}")
print("不能除以零!")
else:
print(f"结果: {result}")
finally:
print("程序结束!")

这个例子会把错误记录到 app.log 文件,方便排查问题。

Python 错误处理详解的更多相关文章

  1. python之数据类型详解

    python之数据类型详解 二.列表list  (可以存储多个值)(列表内数字不需要加引号) sort s1=[','!'] # s1.sort() # print(s1) -->['!', ' ...

  2. Python字符编码详解,str,bytes

    什么是明文 “明文”是可以是文本,音乐,可以编码成mp3文件.明文可以是图像的,可以编码为gif.png或jpg文件.明文是电影的,可以编码成wmv文件.不一而足. 什么是编码?把明文变成计算机语言 ...

  3. python协程详解

    目录 python协程详解 一.什么是协程 二.了解协程的过程 1.yield工作原理 2.预激协程的装饰器 3.终止协程和异常处理 4.让协程返回值 5.yield from的使用 6.yield ...

  4. Python函数参数详解

    Python函数参数详解 形参与实参 什么是形参 在定义函数阶段定义的参数称之为形式参数,简称形参,相当于变量名. 什么是实参 在调用函数阶段传入的值称为实际参数,简称实参.相当于"变量值& ...

  5. 转2:Python字符编码详解

    1. 字符编码简介 1.1. ASCII ASCII(American Standard Code for Information Interchange),是一种单字节的编码.计算机世界里一开始只有 ...

  6. Python 字符串方法详解

    Python 字符串方法详解 本文最初发表于赖勇浩(恋花蝶)的博客(http://blog.csdn.net/lanphaday),如蒙转载,敬请保留全文完整,切勿去除本声明和作者信息.        ...

  7. python time模块详解

    python time模块详解 转自:http://blog.csdn.net/kiki113/article/details/4033017 python 的内嵌time模板翻译及说明  一.简介 ...

  8. Python中dict详解

    from:http://www.cnblogs.com/yangyongzhi/archive/2012/09/17/2688326.html Python中dict详解 python3.0以上,pr ...

  9. Python开发技术详解(视频+源码+文档)

    Python, 是一种面向对象.直译式计算机程序设计语言.Python语法简捷而清晰,具有丰富和强大的类库.它常被昵称为胶水语言,它能够很轻松的把用其他语言制作的各种模块(尤其是C/C++)轻松地联结 ...

  10. python/ORM操作详解

    一.python/ORM操作详解 ===================增==================== models.UserInfo.objects.create(title='alex ...

随机推荐

  1. C#网络编程(六)----Socket编程模型

    简介 Socket(套接字)是计算机网络中的一套编程接口,是网络编程的核心,它将复杂的网络协议封装为简单的API,是应用层(HTTP)与传输层(TCP)之间的桥梁. 应用程序通过调用Socket AP ...

  2. 浅谈Spring、Spring MVC、Spring Boot和Spring Cloud的关系和区别

      Spring 框架就像一个家族,有众多衍生产品,例如 boot.security.jpa等等.但它们的基础都是Spring的IOC和AOP等.IOC提供了依赖注入的容器,AOP解决了面向横切面编程 ...

  3. IDEA jrebel热部署插件破解-最新版

    前言 JRebel插件2022.4.2及之后版本在线地址激活方式已不可用,所以采用本地地址 + 生成的GUID方式 激活 (本文章写的时候,用的JRebel最新版本2023.2.1) 如果需要在线激活 ...

  4. 雷池WAF离线安装搭建全流程指南(2025年最新版)

    一.环境要求与准备工作 系统要求 ● 操作系统:Debian12+(推荐大版本一致,如内网使用debian12,在线主机也需debian系列) ● CPU架构:x86_64,需支持SSSE3指令集(可 ...

  5. 一看就懂!任务提交的资源判断在Taier中的实践

    Taier 介绍 Taier 是袋鼠云开源项目之一,是一个分布式可视化的DAG任务调度系统. 旨在降低ETL开发成本.提高大数据平台稳定性,大数据开发人员可以在 Taier 直接进行业务逻辑的开发,而 ...

  6. [abc302f] Merge Set

    F - Merge Set 显然要建图 首先,我们有一个粗略的想法,对于同一集合\(S_i\)内的元素,\(S_{i,j}\)与\(S_{i,j+1}\)间连一条无向的标号为\(i\)的边 那么题目显 ...

  7. vue快速入门~必备基础知识(一)下~过滤器

    过滤器指的是 在不改变data的情况下输出需要的格式数据. 基本的调用方法  一个过滤器 {{ message | filterFun }} new Vue({ //... filters:{ fil ...

  8. 前后端分离下 博客接入 gitee、github、微博 第三方登录

    今天将博客的第三方登录写了一下 博客是前后端分离的 前端vue+后端laravel 我在这里会一步步教大家如何理解 aouth 形式的授权登录 完成效果图 项目地址 可以的话帮忙点个 star 博客前 ...

  9. MKL库解线性最小二乘问题(LAPACKE_dgels)

    LAPACK(Linear Algebra PACKage)库,是用Fortran语言编写的线性代数计算库,包含线性方程组求解(AX=B).矩阵分解.矩阵求逆.求矩阵特征值.奇异值等.该库用BLAS库 ...

  10. Flink Watermark示例

    Watermark简介 在 Apache Flink 中,水印(Watermark) 是一种用于处理事件时间(Event Time)流数据的机制.它代表了流处理系统中对事件时间进度的理解,用来标识数据 ...