百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术文章 > 正文

Python 异常处理魔法手册:try - except 的终极艺术

itomcoil 2025-06-15 17:00 9 浏览

对话实录

小白:(崩溃)我的程序一遇到错误就崩溃,怎么办?

专家:(掏出魔法书)用 try - except,让程序优雅地处理错误

当我们写的python程序遇到意想不到的问题的时候(比如出现了bug),如果程序不做处理,程序就会异常停止,此时我们可以使用try语句来捕获这些异常,不会使程序异常终止。

异常处理基础三连击

1. 基本用法

在 Python 中,try块用于包含可能会引发异常的代码。当try块中的代码引发异常时,程序流程会立即跳转到对应的except块中进行处理。

try:
	num = int(input("请输入数字:"))
 	print(10 / num)

except ValueError:
 	print("输入的不是数字!")

except ZeroDivisionError:
 	print("不能除以0!")

except Exception as e:
 	print(f"{e}")

在这段代码中,int(input("请输入数字:"))尝试将用户输入转换为整数,如果用户输入的不是数字,就会引发ValueError异常,此时会执行第1个except块中的代码。而10 / num如果num为 0,会引发ZeroDivisionError异常,由第2个except块处理,最后如果不满足上述错误由第3个except模块处理所有错误。

专家提醒

1.先捕获具体异常,再捕获通用异常!如果先捕获通用异常Exception,那么它会捕获所有异常,导致具体异常的except块永远不会执行。

2.不能只写try语句,最少需要搭配except语句或者finally语句

3.except语句可以写多个

2. else 和 finally

else块在try块没有引发任何异常时执行,finally块无论try块是否有异常,都会执行。

try:
	result = 10 / 2

except ZeroDivisionError:
 	print("除零错误")

else:
 	print("计算成功:", result) # 无异常时执行

finally:
 	print("执行完毕") # 无论是否有异常都执行

这里10 / 2不会引发异常,所以else块中的代码会执行,最后finally块也会执行。

三大实战案例

案例 1:文件操作

在文件操作中,可能会遇到文件不存在或者没有权限读取的情况。

try:
  with open("data.txt") as f:
		content = f.read()

except FileNotFoundError:
	print("文件不存在!")

except PermissionError:
	print("没有读取权限!")

else:
	process(content)

with open("data.txt") as f尝试打开文件,如果文件不存在,会引发FileNotFoundError异常;如果没有权限,会引发PermissionError异常。若成功打开并读取文件,else块中的process(content)会对文件内容进行处理。

案例 2:API 请求

使用requests库进行 API 请求时,可能会遇到请求超时或其他错误。

import requests
try:
 	response = requests.get("https://api.example.com/data", timeout = 5)
 	response.raise_for_status() # 检查HTTP错误

except requests.Timeout:
 	print("请求超时!")

except requests.RequestException as e:
 	print(f"请求失败:{e}")

else:
 	print(response.json())

requests.get("
https://api.example.com/data", timeout = 5)尝试发送请求,若 5 秒内未得到响应,会引发requests.Timeout异常。response.raise_for_status()会检查 HTTP 状态码,如果状态码表示请求失败(如 404、500 等),会引发requests.RequestException异常。若请求成功,else块会打印响应的 JSON 数据。

案例 3:数据库操作

使用sqlite3进行数据库操作时,可能会遇到各种数据库相关的错误。

import sqlite3
try:
 	conn = sqlite3.connect("test.db")
 	cursor = conn.cursor()
 	cursor.execute("SELECT * FROM users")

except sqlite3.OperationalError as e:
	print(f"数据库错误:{e}")

else:
 	print(cursor.fetchall())

finally:
	conn.close()

sqlite3.connect("test.db")尝试连接数据库,如果连接失败或者执行 SQL 语句时出现操作错误,会引发sqlite3.OperationalError异常。若操作成功,else块会打印查询结果,最后无论是否有异常,finally块都会关闭数据库连接。

四大血泪陷阱

捕获所有异常

直接使用except:会捕获所有异常,包括SystemExit等系统级异常,这可能导致程序无法正常退出或出现难以调试的问题。

try:
	risky_code()

except: #  捕获所有异常,包括SystemExit
	print("出错了")

正确做法是捕获Exception,它捕获所有非系统异常。

try:
	risky_code()
except Exception as e: #  捕获所有非系统异常
 	print(f"错误:{e}")

忽略异常

在except块中直接使用pass会吞掉异常,导致错误信息丢失,难以排查问题。

try:
	risky_code()
except: #  吞掉异常
	pass

正确做法是记录错误并重新抛出,以便上层调用者处理。

try:
	risky_code()
except Exception as e:
	log_error(e) # 记录错误
	raise # 重新抛出

finally 中的 return

在函数中,如果finally块中有return语句,它会覆盖try块中的return。

def test():
    try:
	    return 1
    finally:
		  return 2 #  覆盖了try中的return
print(test()) # → 2

这通常不是预期的行为,应避免在finally块中使用return,除非确实有特殊需求。

专家工具箱

1. 自定义异常

当 Python 内置的异常类型不能满足需求时,可以自定义异常。

先看下我们平常用到的异常比如AssertionError,SyntaxError,ZeroDivisionError,NameError等,在python的自带文件builtins.py中类似如下定义:

每个异常类继承了父类Exception,看上去定义很简单。

下面我们通过同一个示例来定义一个自定义的异常类,并在程序中抛出异常。

举例:编写一个猜数字的小游戏,输入数字范围为1-100,当输入的数字不在该范围内时会抛出异常;猜对的时候程序停止;猜错了可以继续猜,不限制次数。

1 定义一个输入异常的类

class InputError(Exception):
""" Input failed."""

   def __init__(self, *args, **kwargs):
      pass

2 编写猜数字游戏,并通过raise语句抛出异常

def guess_number():
  #定义数字5
  num = 5
  while True:
     print(f'请输入的数字')
     #input函数输入默认为字符串
     number = int(input())  
     print(f'输入的数字为{number}')

     if number < 0 or number > 100:
        raise InputError
  
     if num == number:
        print(f'猜对了数字为{num},游戏结束')
        break
     else:
        print(f'没有猜对奥,请继续猜吧')

3 执行函数guess_number(),当我们在屏幕中输入数字-1或者101时,程序会抛出异常如下

4 通过try捕获自定义的异常

try:
   guess_number()
except InputError:
   print('输入的数字不能小于0,大于100')

当执行程序并重新输入数字101时,程序捕获到异常并打印如下:

2. 异常链

异常链可以在捕获一个异常后,引发另一个异常,并保留原始异常的信息。

try:
	risky_code()
except ValueError as e:
	raise RuntimeError("处理失败") from e

这样在捕获ValueError后,引发RuntimeError,并且通过from e保留了ValueError的信息,便于调试。

3. 上下文管理器

上下文管理器通过__enter__和__exit__方法来管理资源的分配和释放,在__exit__方法中可以处理异常。

class SafeOperation:
    def __enter__(self):
        return self
    def __exit__(self, exc_type, exc_val, exc_tb):
        if exc_type:
            print(f"捕获异常:{exc_val}")    
            return True # 抑制异常

with SafeOperation():
	risky_code()

当with块中的risky_code()引发异常时,__exit__方法会捕获并处理异常,return True表示抑制异常,不再向上层抛出。

小白:(献上膝盖)原来异常处理这么强大!

专家:(扶起小白)记住:异常处理不是万能的,但没有它是万万不能的!

相关推荐

Java 如何从一个 List 中随机获得元素

概述从一个List中随机获得一个元素是有关List的一个基本操作,但是这个操作又没有非常明显的实现。本页面主要向你展示如何有效的从List中获得一个随机的元素和可以使用的一些方法。选择一个...

想月薪过万吗?计算机安卓开发之&quot;集合&quot;

集合的总结:/***Collection*List(存取有序,有索引,可以重复)*ArrayList*底层是数组实现的,线程不安全,查找和修改快,增和删比较慢*LinkedList*底层是...

China Narrows AI Talent Gap With U.S. as Research Enters Engineering Phase: Report

ImagegeneratedbyAITMTPOST--ChinaisclosinginontheU.S.intheAIindustry-academia-research...

大促系统优化之应用启动速度优化实践

作者:京东零售宋维飞一、前言本文记录了在大促前针对SpringBoot应用启动速度过慢而采取的优化方案,主要介绍了如何定位启动速度慢的阻塞点,以及如何解决这些问题。希望可以帮助大家了解如何定位该类问...

MyEMS开源能源管理系统核心代码解读004

本期解读:计量表能耗数据规范化算法:myems/myems-normalization/meter.py代码见底部这段代码是一个用于计算和存储能源计量数据(如电表读数)的小时值的Python脚本。它主...

Java接口与抽象类:核心区别、使用场景与最佳实践

Java接口与抽象类:核心区别、使用场景与最佳实践一、核心特性对比1.语法定义接口:interface关键字定义,支持extends多继承接口javapublicinterfaceDrawabl...

超好看 vue2.x 音频播放器组件Vue-APlayer

上篇文章给大家分享了视频播放器组件vue-aliplayer,这次给大家推荐一款音频插件VueAplayer。vue-aplayer一个好看又好用的轻量级vue.js音乐播放器组件。清爽漂亮的U...

Linq 下的扩展方法太少了,MoreLinq 来啦

一:背景1.讲故事前几天看同事在用linq给内存中的两个model做左连接,用过的朋友都知道,你一定少不了一个叫做DefaultIfEmpty函数,这玩意吧,本来很流畅的from......

MapReduce过程详解及其性能优化(详细)

从JVM的角度看Map和ReduceMap阶段包括:第一读数据:从HDFS读取数据1、问题:读取数据产生多少个Mapper??Mapper数据过大的话,会产生大量的小文件,由于Mapper是基于虚拟...

手把手教你使用scrapy框架来爬取北京新发地价格行情(实战篇)

来源:Python爬虫与数据挖掘作者:霖hero前言关于Scrapy理论的知识,可以参考我的上一篇文章,这里不再赘述,直接上干货。实战演练爬取分析首先我们进入北京新发地价格行情网页并打开开发者工具,如...

屏蔽疯狂蜘蛛,防止CPU占用100%(mumu模拟器和雷电模拟器哪个更占用cpu)

站点总是某个时间段莫名的cpu100%,资源占用也不高,这就有必要怀疑爬虫问题。1.使用"robots.txt"规范在网站根目录新建空白文件,命名为"robots.txt&#...

Web黑客近年神作Gospider:一款基于Go语言开发的Web爬虫,要收藏

小白看黑客技术文章,一定要点首小歌放松心情哈,我最爱盆栽!开始装逼!Gospider是一款运行速度非常快的Web爬虫程序,对于爱好白帽黑客的小白来说,可谓是佳作!Gospider采用厉害的Go语言开发...

用宝塔面板免费防火墙屏蔽织梦扫描网站

今天教大家在免费的基础上屏蔽织梦扫描,首先您要安装宝塔面板,然后再安装免费的防火墙插件,我用的是Nginx免费防火墙,然后打开这个插件。设置GET-URL过滤设置一条简单的宝塔面板的正则规则就可以屏蔽...

蜘蛛人再捞4千万美元 连续三周蝉联北美票房冠军

7月15日讯老马追踪票房数据的北美院线联盟今天表示,“蜘蛛人:离家日”(Spider-Man:FarFromHome)击退两部新片的挑战,连续第2周勇夺北美票房冠军,海捞4530万美元。法新...

夏天到了,需要提防扁虱,真是又小又恐怖的动物

夏天马上要到了,你知道吗,扁虱是这个夏天最危险的动物之一,很少有动物能比它还凶猛。Whenitcomestosummer'slittledangers,fewarenastiert...