一文速速搞懂Python的异常
off999 2024-11-19 08:33 46 浏览 0 评论
人生之事,不如意者十之有九。
在编程中亦是如此。异常(Exception),遍布于程序各个角落,开发工作的大部分coding,都是为了应对和解决它。
概念
异常,简而言之,是程序在执行期间发生的非预期的、非正常的事件或情况。
举个实际生活的例子:
你周末出门买大龙虾,但当你决定要买哪一只时,你发现没带钱包,那么买大龙虾就是程序要执行的逻辑,而没带钱包就是异常情况。
但异常是一种有一定解决应对方法的错误,就像没带钱包也有可能买得了大龙虾,比如你可以向老板赊账或者暂时借熟人的钱来买。
所以,异常并不一定会完全阻止要完成的事情,有时可能是在提示存在的问题和引导出新的解决方法,应该辩证地去面对它。
产生原因
编程中这些异常的产生可能源自于各种各样的源头,可能是用户提供了错误的输入数据(外因),也可能是系统本身存在逻辑错误(内因)。当这样的异常出现时,如果不加以妥善处理,程序的执行流程将会被强行打断,进而可能引发程序崩溃、数据丢失等严重后果。
家族类型
Python内置了丰富多样的异常类型,每种类型都对应着特定的错误场景。以下是一些常见的异常类型:
- SyntaxError(语法错误):当代码存在不符合 Python 语法规则的地方时就会引发。例如,遗漏了必要的括号、引号等。
- NameError(名称错误):当尝试使用一个未定义的变量或函数时产生。
- TypeError(类型错误):操作中数据类型不匹配导致,比如对一个字符串使用数学运算,1 + "1"。
- ValueError(值错误):提供的值不符合要求,如将一个非数字字符串转换为整数, int("a")。
- IndexError(索引错误):在访问列表等数据结构时,使用了超出范围的索引,比如[][10]。
- KeyError(键错误):在字典中查找不存在的键,比如{}["name"]这样访问就会引发。
- AttributeError(属性错误):尝试访问对象上不存在的属性就会引发,比如A类没有name属性,而A.name就会引发此异常。
- ZeroDivisionError(零除错误):尝试除以零就会引发,如1/0。
- IOError(IO错误):输入输出相关的文件流错误, 比如文件流打开异常、网络流访问异常等。
- FileNotFoundError(文件不存在错误):指定的文件不存在就会引发,比如尝试读写不存在的文件,是IOError的一个细分子类。
- ImportError(导入模块错误):Python会按照一定的路径搜索模块文件。如果import的模块文件没有在搜索路径中找到,就会引发ImportError错误,比如from math import zero。
- RuntimeError(运行时错误):RuntimeError是一种运行时异常,表示在程序运行过程中发生了一些无法预期的情况而导致的一般性错误。比如资源不足等
- NotImplementedError(未实现方法异常):当一个方法或操作尚未实现就会引发,比如图形父类要求计算面积方法必须实现(父类方法写着raise NotImplementedError("子类必须实现这个方法")),那么继承了图形父类的三角形子类如果不实现计算面积方法就会引发。
- IndentationError(缩进错误):代码格式缩进不正确的地方会引发,是SyntaxError的细分子类。
- KeyboardInterrupt(键盘中断):当键盘按下Ctrl+C时会引发捕获
需要注意的是,BaseException是所有异常的基类(注意,不是Exception)。它包括了系统退出相关的异常(如 SystemExit)以及异常中断相关的异常(如 KeyboardInterrupt)等。它位于异常层次结构的最顶端。
而Exception继承自BaseException,是大多数用户自定义异常和Python内置异常的直接或间接基类,其他常见的异常如 IOError、ValueError、TypeError 等都属于 Exception 及其子类。
处理方法
内置异常处理
为了有效地应对这些异常情况,Python 提供了一套强大且灵活的异常处理机制,而其中的核心就是 try-except 语句结构,以及另外两种特殊情况:try-except-else和try-except-finally。 以下是一个面对ZeroDivisionError(零除错误) 异常的处理示例:
# try-except 示例
try:
a = 10 / 0 # 会引发异常
except ZeroDivisionError: # 尝试除以零就会引发——零除错误
print("捕获到除以零错误")
# try-except-else 示例
try:
b = 10 / 2
except ZeroDivisionError:
print("捕获到除以零错误")
else:
print("在 try 块中没有发生异常时执行这里:", b)
# try-except-finally 示例
try:
c = 5 / 1
except ZeroDivisionError:
print("捕获到除以零错误")
finally:
print("无论是否发生异常都会执行这里")
- try-except:主要用于捕获和处理特定的异常,当异常发生时执行相应的 except 代码块。
- try-except-else:在 try 中没有异常发生时,会执行 else 中的代码,它将正常执行的情况和异常处理的情况进行了更明确的区分。
- try-except-finally:无论是否发生异常,finally 中的代码一定会执行,通常用于进行一些无论如何都要完成的清理或收尾工作。比如关闭文件、释放资源等。
这些内置异常还支持自定义异常消息和主动raise
number = "a"
try:
if not number.isnumeric():
raise ValueError("该字符串不能转成数值")
except ValueError as e:
print(e)
# Outputs
# 该字符串不能转成数值
自定义异常
在现实开发中,python的内置异常类型不足以满足业务上的细分情况,有些是属于规则异常,如输入的邮箱不满足规则要求,这时候就需要引入自定义异常了。
自定义异常实现通常有以下流程:
- 首先,定义一个继承自Exception的自定义异常类,在类中可以添加一些与该异常相关的属性和构造方法来定制异常信息。
- 然后,编写一个用于执行具体校验操作的函数,当校验不通过时,主动通过raise抛出自定义异常。
- 在使用的地方,将可能引发异常的代码放在try块中,然后针对自定义异常进行捕获和处理
下面举个web开发中常见的检查邮箱格式例子:
import re
class InvalidEmailException(Exception):
"""自定义异常类"""
def __init__(self, email):
self.email = email
super().__init__(f"无效的邮箱: {email}")
def validate_email(email):
# 实用正则表达式校验邮箱格式
pattern = r'^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+#39;
if not re.match(pattern, email):
raise InvalidEmailException(email)
try:
# 校验邮箱格式
validate_email("invalid_email")
except InvalidEmailException as e:
# 捕获到邮箱格式的异常并处理(这里的处理仅仅是打印相关信息)
print(e)
# Outputs
# 无效的邮箱: invalid_email
无法处理的异常
对于一些无法预料的异常,通常需要一个大的try-catch进行捕获,并打印记录到日志系统和告警系统,然后再进一步收集、分析、处理。
应用场景
文件操作
当我们尝试打开一个不存在的文件进行读取或写入时,就可能引发 FileNotFoundError 异常。通过异常处理,我们可以优雅地处理这种情况,比如提示用户文件不存在并引导他们采取正确的行动。
try:
with open('file.txt', 'r') as f:
content = f.read()
except FileNotFoundError:
print("文件不存在!")
网络通信
在与网络服务进行交互的过程中,网络连接问题、服务器错误等都可能导致异常的产生。及时捕获和处理(如重试)这些异常能够让我们的程序更加稳定和可靠。
import requests
try:
response = requests.get('http://example.com')
except requests.exceptions.RequestException as e:
print(f"网络请求出错: {e}")
用户输入验证
我们可以利用异常处理来确保用户输入的合法性。当用户输入不符合要求的数据时,引发异常并提示用户重新输入,直到输入正确为止。
while True:
try:
age = int(input("请输入你的年龄: "))
break
except ValueError:
print("请输入有效的整数!")
数据库操作
在与数据库进行交互时,可能会遇到连接问题、查询错误等异常情况。通过合理的异常处理,可以保障程序在面对这些问题时依然能够正常运行。
资源管理
当获取或释放系统资源时,如内存、锁等,如果操作出现问题,异常处理可以帮助我们确保资源的正确管理和释放,避免资源泄漏等问题。
外部依赖
当程序依赖于其他外部组件或服务时,如第三方库、外部系统接口等,这些外部因素可能会出现故障或异常。通过异常处理,可以在一定程度上隔离这些外部问题,使我们的程序更具弹性。
业务异常
当程序执行时需要满足某些条件规则,比如需要用户登录后才能进行的操作,如果用户不登录,可能有些功能无权操作。这时我们可以把这种情况视为一种业务异常抛出给用户,并提示引导用户去登录。
在web开发中,有时会通过middleware(中间件/拦截器)或者装饰器的方式对应一些业务异常进行统一捕获,当这些业务异常被抛出时,就会寻找对应方法来处理或引导解决,下面通过一个多种异常统一捕获和处理例子说明下:
class WebError(Exception):
def handle(self):
# 最后的底牌处理
print("服务器升级中")
class NotLoginError(WebError):
def handle(self):
# 处理未登录的逻辑,比如跳转登录链接
print("跳转登录页面")
class InputError(WebError):
def handle(self):
# 提示输入有问题的逻辑处理
print("输入有问题,重新输入")
def web_middleware(func):
def inner(*args, **kwargs):
try:
return func(*args, **kwargs)
except WebError as e:
# 捕获到异常,并使用多态进行对应处理
if isinstance(e, WebError):
return e.handle()
except Exception: # 无法预测的异常
WebError().handle()
return inner
# --------------------------- web 接口逻辑 ----------------------------------
@web_middleware
def get_user_info(s):
"""获取用户信息"""
if s == 1:
# 假设拿不到用户信息
raise NotLoginError()
elif s == 2:
# 假设用户输入ID不正确
raise InputError()
elif s == 3:
# 假设计算逻辑出错
s / 0
else:
print("获取用户信息成功")
for i in range(1, 5):
get_user_info(i)
# Output
# 跳转登录页面
# 输入有问题,重新输入
# 服务器升级中
# 获取用户信息成功
总结
程序中的异常,恰似人生旅途中的坎坷波折,它们在某些时候反而能促使我们的系统不断磨砺成长,迈向更加健壮与稳定的境界。故而,请以正确的态度和方式“珍视”并“善待”异常。
各位彦祖亦菲,你是怎么看待异常的呢?
相关推荐
- Kubernetes 核心概念全景图:Pod、Node、Cluster、Control Plane 等
-
想真正读懂Kubernetes的底层运作,你必须理解它的“权力架构”。Pod是什么?Node是什么?ControlPlane又是做什么的?它们之间有什么关系?怎么协同工作?本篇带你构建一个...
- Helm 实战:用 Helm 部署一个 Nginx 应用
-
这一篇,我们将动手实战:用Helm从零部署一个Nginx应用,并掌握HelmChart的结构和参数化技巧。一、准备环境在开始之前,你需要确保环境中具备以下工具:已部署的Kubernet...
- 从零开始:如何在 Linux 上搭建 Nginx + Node.js 高性能 Web 服务
-
在现代互联网服务架构中,Nginx+Node.js已成为轻量级、高性能网站的首选组合。本文将带你从零开始,一步步搭建一个高并发、高可用的Web服务平台,让新手也能轻松掌握生产级部署思路。一、...
- NetBox 最新版 4.4.1 完整安装指南
-
NetBox最新版4.4.1完整安装指南(修正版)by大牛蛙1.系统准备#关闭SELinux和防火墙(仅测试环境)systemctldisable--nowfirewalldse...
- Termux 安装 linux 宝塔面板,搭建 Nginx+PHP+Mysql web 网站环境
-
Termux安装linux宝塔面板,搭建Nginx+PHP+Mysqlweb服务环境,解决启动故障奶妈级教程1.到宝塔面板官网:https://www.bt.cn/new/download...
- OpenEuler系统安装Nginx安装配置_openwrt安装nginx
-
NginxWEB安装时可以指定很多的模块,默认需要安装Rewrite模块,也即是需要系统有PCRE库,安装Pcre支持Rewrite功能。如下为安装NginxWEB服务器方法:源码的路径,而不是编...
- 多级缓存架构实战:从OpenResty到Redis,打造毫秒级响应系统
-
在传统的Web架构中,当用户发起请求时,应用通常会直接查询数据库。这种模式在低并发场景下尚可工作,但当流量激增时,数据库很容易成为性能瓶颈。多级缓存通过在数据路径的不同层级设置缓存,可以显著降低数据库...
- 如何使用 Nginx 缓存提高网站性能 ?
-
快速加载的站点提供了更好的用户体验并且可以拥有更高的搜索引擎排名。通过Nginx缓存提高你的网站性能是一个有效的方法。Nginx是一个流行的开源web服务器,也可以作为web服务器反向代...
- 如何构建企业级Docker Registry Server
-
很多人问我,虚拟机镜像和docker镜像的区别是什么?其实区别非常明显,我们可以通过阅读Dockerfile文件就可以知道这个镜像都做了哪些操作,能提供什么服务;但通过虚拟机镜像,你能一眼看出来虚拟机...
- 如何解决局域网SSL证书问题?使用mkcert证书生成工具轻松搞定
-
“局域网里弹出‘不安全’红锁,老板就在身后盯着演示,那一刻只想原地消失。”别笑,九成前端都经历过。自签证书被Chrome标红,客户以为网站被黑,其实只是缺一张被信任的证。mkcert把这事从半小时缩到...
- Docker 安全与权限控制:别让你的容器变成“漏洞盒子”
-
在享受容器带来的轻量与灵活的同时,我们也必须面对一个现实问题:安全隐患。容器并不是天然安全,错误配置甚至可能让攻击者“越狱”入侵主机!本篇将带你从多个层面强化Docker的安全防护,构建真正可放心...
- Kubernetes生产级管理指南(2025版)
-
在云原生技术持续演进的2025年,Kubernetes已成为企业数字化转型的核心引擎。然而,生产环境中的集群管理仍面临基础设施配置、安全漏洞、运维复杂度攀升等挑战。本文将结合最新行业实践,从基础设施即...
- 云原生工程师日常使用最多的工具和100条高频命令
-
在云原生时代,工程师不仅要熟悉容器化、编排和服务网格,还要掌握大量工具和命令来进行日常运维与开发。本文将从工具篇和命令篇两个角度,详细介绍云原生工程师每天都会用到的核心技能。一、云原生工程师常...
- 用 Jenkins 实现自动化 CI/CD_jenkins api自动执行
-
场景设定(可替换为你的技术栈)语言:Node.js(示例简单,任何语言思路一致)制品:Docker镜像(推送到DockerHub/Harbor)运行环境:Kubernetes(staging...
- 5款好用开源云笔记虚拟主机部署项目推荐
-
在个人数据管理与协同办公场景中,开源云笔记项目凭借可自主部署、数据可控的优势,成为众多用户的首选。以下推荐5款适配虚拟主机部署、功能完善的开源项目,附核心特性与部署要点,助力快速搭建专属云笔记系统。...
你 发表评论:
欢迎- 一周热门
- 最近发表
-
- Kubernetes 核心概念全景图:Pod、Node、Cluster、Control Plane 等
- Helm 实战:用 Helm 部署一个 Nginx 应用
- 从零开始:如何在 Linux 上搭建 Nginx + Node.js 高性能 Web 服务
- NetBox 最新版 4.4.1 完整安装指南
- Termux 安装 linux 宝塔面板,搭建 Nginx+PHP+Mysql web 网站环境
- OpenEuler系统安装Nginx安装配置_openwrt安装nginx
- 多级缓存架构实战:从OpenResty到Redis,打造毫秒级响应系统
- 如何使用 Nginx 缓存提高网站性能 ?
- 如何构建企业级Docker Registry Server
- 如何解决局域网SSL证书问题?使用mkcert证书生成工具轻松搞定
- 标签列表
-
- python计时 (73)
- python安装路径 (56)
- python类型转换 (93)
- python进度条 (67)
- python吧 (67)
- python的for循环 (65)
- python格式化字符串 (61)
- python静态方法 (57)
- python列表切片 (59)
- python面向对象编程 (60)
- python 代码加密 (65)
- python串口编程 (77)
- python封装 (57)
- python写入txt (66)
- python读取文件夹下所有文件 (59)
- python操作mysql数据库 (66)
- python获取列表的长度 (64)
- python接口 (63)
- python调用函数 (57)
- python多态 (60)
- python匿名函数 (59)
- python打印九九乘法表 (65)
- python赋值 (62)
- python异常 (69)
- python元祖 (57)