Python 异常处理:捕获与处理常见异常
Python 程序在运行过程中可能因各种原因出错,比如文件不存在、用户输入了无效数据、网络连接失败等。这些错误被称为“异常”。如果不处理,程序会直接崩溃。使用 try...except 语句可以捕获异常并优雅地处理它们,避免程序意外终止。
基础异常处理结构
- 编写
try块:将可能出错的代码放在try后面。 - 编写
except块:指定要捕获的异常类型,并定义应对措施。 - 可选添加
else块:仅当try中没有异常时才执行。 - 可选添加
finally块:无论是否发生异常都会执行,常用于清理资源(如关闭文件)。
try:
# 可能出错的代码
result = 10 / 0
except ZeroDivisionError:
# 处理除零错误
print("不能除以零!")
else:
# 没有异常时执行
print(f"结果是: {result}")
finally:
# 总是执行
print("计算完成。")
运行上述代码,输出为:
不能除以零!
计算完成。
捕获多种常见异常
实际开发中,一段代码可能触发多种不同类型的异常。使用多个 except 子句可以分别处理不同错误。
try:
num = int(input("请输入一个整数: "))
result = 100 / num
print(f"100 除以 {num} 等于 {result}")
except ValueError:
print("输入的不是有效整数!")
except ZeroDivisionError:
print("不能除以零!")
except Exception as e:
print(f"发生了未预期的错误: {e}")
- 如果用户输入
"abc",会触发ValueError。 - 如果输入
0,会触发ZeroDivisionError。 - 其他未预料的错误由通用的
Exception捕获。
注意:
except Exception应放在所有具体异常之后,否则会“吞掉”本应单独处理的错误。
查看常见内置异常类型
Python 提供了丰富的内置异常类。以下是几个最常用的:
| 异常名称 | 触发场景 | 示例 |
|---|---|---|
ValueError |
函数接收到正确类型但值不合法 | int("hello") |
TypeError |
对不支持的操作传入了错误类型 | "a" + 5 |
IndexError |
列表或元组索引超出范围 | [1,2][5] |
KeyError |
字典中找不到指定键 | {"a":1}["b"] |
FileNotFoundError |
尝试打开不存在的文件 | open("no_such.txt") |
ZeroDivisionError |
除法或取模运算中除数为零 | 10 / 0 |
主动抛出异常
有时你需要在特定条件下中断程序流程。使用 raise 关键字可以手动抛出异常。
def divide(a, b):
if b == 0:
raise ValueError("除数不能为零")
return a / b
try:
result = divide(10, 0)
except ValueError as e:
print(f"错误: {e}")
输出:
错误: 除数不能为零
你也可以抛出内置异常的子类,或自定义异常类(见下文)。
自定义异常类
当内置异常无法准确描述你的业务错误时,创建自己的异常类能让代码更清晰。
- 继承
Exception类。 - 通常只需定义
__init__方法和错误信息。
class InvalidAgeError(Exception):
def __init__(self, age):
self.age = age
super().__init__(f"年龄 {age} 不合法,必须在 0 到 150 之间")
def set_age(age):
if age < 0 or age > 150:
raise InvalidAgeError(age)
print(f"年龄设置为: {age}")
try:
set_age(-5)
except InvalidAgeError as e:
print(e)
输出:
年龄 -5 不合法,必须在 0 到 150 之间
安全读取文件的最佳实践
文件操作极易引发异常(如文件不存在、权限不足)。结合 try...except 和 with 语句可确保资源安全释放。
filename = "data.txt"
try:
with open(filename, 'r', encoding='utf-8') as f:
content = f.read()
print(content)
except FileNotFoundError:
print(f"文件 {filename} 不存在")
except PermissionError:
print(f"没有权限读取文件 {filename}")
except UnicodeDecodeError:
print(f"文件 {filename} 编码格式不支持")
with open(...)确保文件在使用后自动关闭,即使发生异常。- 分别捕获
FileNotFoundError、PermissionError等具体错误,提供明确提示。
避免空的 except 块
永远不要写裸露的 except:,因为它会捕获包括系统退出(KeyboardInterrupt、SystemExit)在内的所有异常,导致程序无法正常终止。
❌ 错误示例:
try:
risky_operation()
except: # 危险!会隐藏所有错误
pass
✅ 正确做法:
try:
risky_operation()
except SpecificError:
handle_error()
如果确实需要捕获所有非系统异常,使用 except Exception:。
记录异常日志
在生产环境中,将异常信息写入日志比直接打印到控制台更有用。
import logging
logging.basicConfig(level=logging.ERROR)
try:
value = int("not_a_number")
except ValueError as e:
logging.error("转换失败", exc_info=True)
exc_info=True 会记录完整的异常堆栈,便于调试。
异常链:保留原始错误信息
当你在处理一个异常时又引发了新异常,使用 raise ... from ... 可以保留原始错误上下文。
def process_data(data):
try:
return int(data)
except ValueError as e:
raise RuntimeError("数据处理失败") from e
try:
process_data("xyz")
except RuntimeError as e:
print(f"新异常: {e}")
print(f"原始异常: {e.__cause__}")
输出显示新旧两个异常,帮助追踪问题根源。
不要过度使用异常控制流程
异常机制不应替代常规逻辑判断。频繁使用异常会影响性能,且降低代码可读性。
❌ 不推荐:
try:
value = my_dict["key"]
except KeyError:
value = "default"
✅ 推荐:
value = my_dict.get("key", "default")
仅在真正“异常”的情况下使用异常处理,而非作为常规分支手段。

暂无评论,快来抢沙发吧!