错误 vs. 异常
在 Python 中,我们通常区分两种情况:

错误
错误通常是更严重的问题,导致程序无法继续运行,它们不是由异常处理机制捕获的,而是直接终止程序。
- 语法错误:这是最常见的错误,在你编写代码时,如果不符合 Python 的语法规则,解释器在运行前就会报错。
- 内存错误:当程序没有足够的内存可以分配时会发生,
MemoryError。
示例:语法错误
# 缺少冒号
if True
print("Hello")
运行后会立即报错:
File "<stdin>", line 1
if True
^
SyntaxError: invalid syntax
异常
异常是程序在运行时发生的错误,它不会直接终止程序,而是创建一个“异常对象”并“抛出”它,如果程序中没有处理这个异常,程序就会崩溃并打印出 Traceback 信息。

Python 内置了大量的异常类型,
NameError: 尝试访问一个未定义的变量。TypeError: 对类型不兼容的对象执行操作。ValueError: 传递给函数的参数类型正确,但值不合适。IndexError: 访问序列中不存在的索引。KeyError: 访问字典中不存在的键。FileNotFoundError: 尝试打开一个不存在的文件。ZeroDivisionError: 除数为零。
示例:各种异常
# NameError
print(undefined_var)
# TypeError
result = '5' + 2
# ValueError
num = int('abc')
# IndexError
my_list = [1, 2, 3]
print(my_list[5])
# KeyError
my_dict = {'a': 1, 'b': 2}
print(my_dict['c'])
# FileNotFoundError
with open('non_existent_file.txt', 'r') as f:
content = f.read()
# ZeroDivisionError
print(10 / 0)
任何一个 print 语句都会导致程序崩溃,并显示类似下面的 Traceback:
Traceback (most recent call last):
File "your_script.py", line X, in <module>
print(undefined_var)
NameError: name 'undefined_var' is not defined
异常处理机制
为了防止程序因为异常而崩溃,Python 提供了 try...except 结构来捕获和处理异常。

try...except 基本结构
这是最核心的异常处理结构。
try:
# 尝试执行的代码块
# 这里的代码可能会抛出异常
code_that_might_fail()
except SomeException as e:
# try 块中抛出了 SomeException 类型的异常,
# 则执行这里的代码块
# 变量 e 会接收到异常对象
handle_the_exception(e)
示例:优雅地处理文件不存在
filename = 'data.txt'
try:
f = open(filename, 'r')
content = f.read()
print(content)
f.close()
except FileNotFoundError:
print(f"错误:文件 '{filename}' 未找到,请检查文件名是否正确。")
print("程序继续执行...")
即使 data.txt 文件不存在,程序也不会崩溃,而是会打印出友好的错误提示,并继续执行后面的代码。
捕获多种异常
一个 try 块中可能发生多种不同的异常,你可以使用多个 except 块来分别处理它们。
a = 10
b = '0' # 如果改为 0, 则是 ZeroDivisionError; 如果改为 2, 则是 TypeError
try:
result = a / b
print(f"结果是: {result}")
except ZeroDivisionError:
print("错误:不能除以零!")
except TypeError:
print("错误:不能将整数和字符串进行除法运算。")
finally 子句
finally 块中的代码无论是否发生异常,都会被执行,它通常用于执行“清理”操作,比如关闭文件、释放数据库连接等。
file = None
try:
file = open('data.txt', 'r')
# 假设这里发生了异常
print(file.read())
except FileNotFoundError:
print("文件未找到!")
finally:
# 无论 try 块成功还是失败,这里都会执行
if file:
file.close()
print("文件已关闭。")
print("程序结束。")
raise 主动抛出异常
除了 Python 解释器会自动抛出异常,我们也可以使用 raise 语句主动抛出异常。
def check_age(age):
if not isinstance(age, int):
raise TypeError("年龄必须是整数")
if age < 0:
raise ValueError("年龄不能是负数")
if age < 18:
print("未成年")
else:
print("已成年")
# 正常调用
check_age(20)
# 主动抛出异常
try:
check_age(-5)
except ValueError as e:
print(f"捕获到异常: {e}")
try:
check_age("twenty")
except TypeError as e:
print(f"捕获到异常: {e}")
Python 内置异常层次结构
所有内置异常都继承自 BaseException 类,了解这个层次结构有助于你更好地选择要捕获的异常类型。
BaseException
+-- SystemExit
+-- KeyboardInterrupt
+-- GeneratorExit
+-- Exception
+-- StopIteration
+-- ArithmeticError
| +-- FloatingPointError
| +-- OverflowError
| +-- ZeroDivisionError
+-- LookupError
| +-- IndexError
| +-- KeyError
+-- AttributeError
+-- TypeError
+-- ValueError
+-- ... (还有很多其他类型)
最佳实践:捕获具体的异常
永远不要使用一个裸露的 except: 来捕获所有异常,这可能会隐藏你程序中的严重问题(SystemExit 或 KeyboardInterrupt)。
不好的做法:
try:
# 一些代码
pass
except: # 捕获所有异常,包括程序退出信号
pass
好的做法:
try:
# 一些代码
pass
except ValueError as e:
# 只处理值错误
print(f"发生值错误: {e}")
except KeyError as e:
# 只处理键错误
print(f"发生键错误: {e}")
except Exception as e:
# 捕获其他所有预料之外的异常,并记录下来
print(f"发生未知错误: {e}")
自定义异常
你可以通过继承 Python 的 Exception 类来创建自己的异常类型,这能让你的代码更具可读性和可维护性。
class InsufficientFundsError(Exception):
"""当账户余额不足时抛出此异常。"""
def __init__(self, balance, amount):
self.balance = balance
self.amount = amount
message = f"余额不足,当前余额: {balance}, 尝试取款: {amount}"
super().__init__(message)
class BankAccount:
def __init__(self, balance=0):
self.balance = balance
def withdraw(self, amount):
if amount > self.balance:
# 主动抛出自定义异常
raise InsufficientFundsError(self.balance, amount)
self.balance -= amount
print(f"成功取款 {amount},当前余额: {self.balance}")
# 使用自定义异常
account = BankAccount(100)
try:
account.withdraw(50)
print("取款成功。")
account.withdraw(100) # 这行会抛出异常
except InsufficientFundsError as e:
print(f"取款失败: {e}")
# 可以在这里进行恢复操作,比如通知用户等
| 概念 | 作用 | 示例 | |
|---|---|---|---|
| 错误 | SyntaxError, MemoryError |
严重问题,程序无法继续 | if True print('hi') |
| 异常 | NameError, TypeError, ValueError |
运行时错误,可被捕获处理 | int('hello') |
| 捕获异常 | try...except |
防止程序崩溃,处理错误 | try: ... except ValueError: ... |
| 清理操作 | finally |
无论是否出错都执行 | finally: file.close() |
| 主动抛出 | raise |
人为地触发一个异常 | raise ValueError("Bad value") |
| 自定义异常 | class MyError(Exception) |
创建特定领域的错误类型 | class InsufficientFundsError(...) |
掌握异常处理是编写专业级 Python 代码的必备技能,记住这个黄金法则:“请求原谅比请求许可更容易”(EAFP: It's Easier to Ask for Forgiveness than Permission),也就是 try...except 风格,而不是在每次操作前都做大量的 if 判断。
