上一期我们拆解了Python异常的核心概念,分清了异常与语法错误的区别,盘点了实战中高频出现的异常类型,知道了异常是程序运行时的“意外状况”,若不处理会直接导致程序崩溃。今天我们正式解锁异常处理的核心语法——try…except,教你用最简单的代码捕获异常、处理异常,让你的代码摆脱“一报错就罢工”的困境,变得更健壮、更容错。
无论是日常练手还是实战开发,try…except都是最基础、最常用的异常处理方式。它的逻辑简单易懂,就像给程序上了一层“防护盾”:提前预判可能出现异常的代码,一旦出现异常,就执行预设的处理逻辑,而非直接崩溃。掌握它的基础用法,就能应对80%以上的异常场景,是从“能写代码”到“能写好代码”的关键一步。
📌 为什么需要try…except?
在没有try…except之前,我们编写的代码一旦触发异常,就会直接终止,抛出刺眼的红色报错信息,不仅影响程序运行,还会让使用者体验极差。
比如我们写一个简单的除法计算程序,若用户输入的除数为0,程序会直接触发ZeroDivisionError,终止运行;再比如读取文件时,若文件路径错误,程序会触发FileNotFoundError,直接崩溃。这些场景下,我们需要一种方式,让程序“遇到问题不慌乱”,而是给出友好提示,甚至继续执行后续代码——这就是try…except的核心作用。
# 未使用try…except,触发异常直接崩溃# 示例1:除数为0,程序终止a = 10b = 0print(a / b) # 触发ZeroDivisionError,程序崩溃,后续代码无法执行print("程序执行完毕") # 这句话不会被打印# 示例2:文件不存在,程序终止with open("test.txt", "r") as f: content = f.read() # 触发FileNotFoundError,程序崩溃
而有了try…except,我们就能捕获这些异常,给出友好的错误提示,让程序继续执行,甚至优雅处理异常,极大提升代码的稳定性和用户体验。这也是try…except最核心的价值——不是避免异常,而是优雅地处理异常。
🔧 try…except 基础语法
try…except的基础语法非常简洁,核心分为两个部分:try块和except块,二者必须成对出现,缺一不可。
# try…except 基础语法try: # 可能触发异常的代码(核心执行代码) 代码块1except 异常类型: # 异常触发后,执行的处理逻辑 代码块2
语法解读:
try块:包裹“可能出现异常”的代码,程序会先执行try块中的内容;
except块:紧跟在try块之后,指定要捕获的异常类型;
执行逻辑:如果try块中的代码正常执行,没有触发异常,那么except块会被跳过,程序继续执行后续代码;如果try块中的代码触发了指定类型的异常,程序会立即停止执行try块中剩余的代码,转而执行except块中的处理逻辑;如果触发的异常不是except指定的类型,程序依然会崩溃,抛出对应异常。
这里需要注意:except后必须指定具体的异常类型(或多个类型),避免使用“万能异常”(后续会详细说明),确保异常处理的精准性。
🔍 3种核心用法
结合上一期我们学到的高频异常,这里拆解try…except的3种基础用法,覆盖日常开发中最常见的场景,每一种都搭配实战案例,一看就会、一用就通。
1. 基础用法:捕获单一特定异常
最常用的用法:明确知道某段代码可能触发哪种异常,就用except指定该异常类型,针对性处理。适合场景:代码逻辑单一,异常类型明确(如除法计算、列表索引访问、字典键访问等)。
# 示例1:捕获ZeroDivisionError(除以零异常)try: a = 10 b = 0 print(a / b) # 可能触发异常的代码except ZeroDivisionError: # 异常触发后的处理逻辑(友好提示) print("错误:除数不能为0,请重新输入有效的除数!")# 异常处理后,程序继续执行后续代码print("程序执行完毕(未崩溃)")# 示例2:捕获IndexError(索引越界异常)try: nums = [1, 2, 3, 4] print(nums[5]) # 可能触发异常的代码except IndexError: print("错误:索引超出范围,请检查索引值是否正确!")print("后续代码正常执行")
核心亮点:针对性强,能精准捕获预期内的异常,同时给出清晰的错误提示,既避免程序崩溃,又方便后续排查问题。
2. 进阶用法:捕获多个特定异常
当一段代码可能触发多种不同类型的异常时,我们可以用多个except块,分别捕获不同的异常,给出不同的处理逻辑;也可以将多个异常类型放在一个except后,统一处理。
两种实现方式,根据实际需求选择,优先推荐第一种(精准处理,体验更好)。
# 方式1:多个except块(推荐,精准处理不同异常)try: # 这段代码可能触发3种异常:IndexError、TypeError、ValueError nums = [1, 2, 3] index = int(input("请输入要访问的索引:")) # 可能触发ValueError(输入非数字) print(nums[index] + "10") # 可能触发IndexError、TypeErrorexcept IndexError: print("错误:索引超出范围!")except TypeError: print("错误:数据类型不匹配,无法进行加法运算!")except ValueError: print("错误:请输入有效的整数索引!")# 方式2:一个except块,捕获多个异常(统一处理)try: nums = [1, 2, 3] index = int(input("请输入要访问的索引:")) print(nums[index] + "10")except (IndexError, TypeError, ValueError): print("输入错误或操作异常,请检查输入和操作是否正确!")
注意:多个except块的顺序很重要,要将“子类异常”放在前面,“父类异常”放在后面(比如UnicodeDecodeError是ValueError的子类,需先捕获前者),否则会导致子类异常无法被精准捕获。
3. 实用用法:捕获异常并获取异常信息
很多时候,我们不仅需要捕获异常、给出提示,还需要知道异常的具体原因,方便后续调试和问题排查。这时可以用“as e”的语法,获取异常的关联值(错误信息),并在处理逻辑中打印。
# 捕获异常并获取错误信息(as e 用法)try: user_info = {"name": "张三", "age": 25} print(user_info["gender"]) # 触发KeyErrorexcept KeyError as e: # e 就是异常的关联值(错误信息) print(f"错误:{e},该键不存在于字典中,请检查键名是否正确!")# 示例2:结合多个异常使用try: a = int(input("请输入第一个数字:")) b = int(input("请输入第二个数字:")) print(a / b)except ZeroDivisionError as e: print(f"除以零异常:{e},除数不能为0!")except ValueError as e: print(f"值错误:{e},请输入有效的整数!")
这种用法在实战中非常实用,既能让程序正常运行,又能精准获取异常原因,大幅提升调试效率,避免“只知道报错,不知道为什么报错”的困境。
✅ try…except 核心执行规则
try块是核心:程序只会执行try块中的代码,一旦触发异常,立即跳转至对应except块,不再执行try块中剩余的代码;
except块匹配规则:只有try块触发的异常,与except指定的异常类型完全一致(或属于其子类),才会执行该except块;
异常捕获顺序:多个except块时,按从上到下的顺序匹配,一旦匹配成功,就不再执行后续的except块;
未捕获的异常:如果try块触发的异常,没有对应的except块捕获,程序依然会崩溃,抛出原始异常信息;
语法要求:try块不能单独存在,必须搭配至少一个except块;except块必须紧跟在try块之后。
# 执行规则示例(理解“一旦匹配,不再执行后续except”)try: print(10 / 0) # 触发ZeroDivisionErrorexcept ZeroDivisionError: print("捕获到除以零异常")except Exception: print("捕获到其他异常") # 不会被执行,因为前面已经匹配到异常# 未捕获异常示例(程序依然崩溃)try: print(10 / 0) # 触发ZeroDivisionErrorexcept IndexError: print("捕获到索引越界异常") # 不匹配,无法捕获# 程序崩溃,抛出ZeroDivisionError
❌ 必避的4个try…except使用坑
try…except看似简单,但在使用过程中,很多开发者容易陷入误区,导致异常处理无效、代码可读性差,甚至掩盖真正的问题,这4个坑一定要避开。
坑1:用try…except捕获语法错误:语法错误是编写时的失误,在程序运行前就会被检测到,try…except无法捕获,无需费力去捕获;
坑2:过度使用“万能异常”:用except Exception(或单独的except)捕获所有异常,会掩盖真正的错误原因,后续排查问题极其困难,应优先捕获特定异常;
坑3:捕获异常后不处理:仅用try…except捕获异常,却不做任何处理(比如只写pass),导致无法定位问题,失去异常处理的意义;
坑4:异常捕获顺序错误:将父类异常放在子类异常前面,导致子类异常无法被精准捕获,比如将except ValueError放在except UnicodeDecodeError前面。
# 避坑示例(必看)# 坑1:捕获语法错误(无效)try: if 10 > 5 # 语法错误(少写冒号),运行前就报错,try无法捕获 print("10大于5")except SyntaxError: print("捕获到语法错误") # 不会执行,因为语法错误在运行前就被检测到# 坑2:过度使用万能异常(错误)try: print(10 / 0)except Exception as e: print("出现异常") # 仅提示异常,无法知道具体是哪种异常、原因是什么# 正确做法:捕获特定异常try: print(10 / 0)except ZeroDivisionError as e: print(f"除以零异常:{e}") # 精准提示# 坑3:捕获异常不处理(错误)try: nums = [1, 2, 3] print(nums[5])except IndexError: pass # 不做任何处理,无法定位问题# 正确做法:给出提示或处理try: nums = [1, 2, 3] print(nums[5])except IndexError as e: print(f"索引越界:{e},请检查索引范围")# 坑4:异常捕获顺序错误(错误)try: raise UnicodeDecodeError('utf-8', b'x80', 0, 1, 'invalid start byte')except ValueError as e: # 父类异常在前,子类异常无法被捕获 print(f"ValueError:{e}")except UnicodeDecodeError as e: print(f"UnicodeDecodeError:{e}") # 不会被执行# 正确做法:子类异常在前try: raise UnicodeDecodeError('utf-8', b'x80', 0, 1, 'invalid start byte')except UnicodeDecodeError as e: print(f"UnicodeDecodeError:{e}")except ValueError as e: print(f"ValueError:{e}")
📝 核心总结
try…except是Python最基础、最常用的异常处理语法,核心作用是捕获异常、处理异常,避免程序崩溃;
3种核心用法:捕获单一特定异常、捕获多个特定异常、捕获异常并获取错误信息,覆盖80%以上的实战场景;
核心规则:try块执行可能异常的代码,except块匹配并处理异常,多个except块按顺序匹配,未匹配到异常则程序崩溃;
避坑重点:不捕获语法错误、不过度使用万能异常、捕获异常后及时处理、注意异常捕获顺序;
实战价值:掌握try…except基础用法,能大幅提升代码的稳定性和容错性,让程序“遇到问题不慌乱”,同时方便后续调试排查。
try…except的基础用法并不复杂,关键在于“精准捕获、合理处理”,结合上一期学到的常见异常,多动手练习,就能熟练运用。下一期我们会进阶学习try…except的拓展用法(try-except-else-finally),解锁更优雅、更全面的异常处理方式。
✨ 小任务:用try…except完善以下代码,捕获可能出现的3种异常(ValueError、ZeroDivisionError、IndexError),并给出友好的错误提示,确保程序不崩溃、能正常执行后续代码。
# 待完善代码nums = [10, 20, 30, 40]a = int(input("请输入第一个数字:"))b = int(input("请输入第二个数字:"))index = int(input("请输入要访问的列表索引:"))print(f"两个数字的商:{a / b}")print(f"列表对应索引的值:{nums[index]}")print("程序执行完毕")
读懂代码的骨架,驾驭AI的血肉,做数字时代的超级个体🔥