目录

第十九章:异常处理

本章目标

完成本章学习后,你将能够:

异常基础

什么是异常

异常是程序执行过程中发生的错误事件,会中断正常程序流程。

# 常见异常
10 / 0                # ZeroDivisionError
int("hello")          # ValueError
"hello"[10]           # IndexError
{"a": 1}["b"]         # KeyError
open("nonexistent")   # FileNotFoundError

异常层次结构

BaseException
 ├── SystemExit
 ├── KeyboardInterrupt
 └── Exception
      ├── ArithmeticError
      │    └── ZeroDivisionError
      ├── LookupError
      │    ├── IndexError
      │    └── KeyError
      ├── TypeError
      ├── ValueError
      ├── RuntimeError
      └── OSError
           └── FileNotFoundError

异常处理

try-except

try:
    result = 10 / 0
except ZeroDivisionError:
    print("Cannot divide by zero!")
 
# 捕获多个异常
try:
    # some code
    pass
except (TypeError, ValueError) as e:
    print(f"Error: {e}")
 
# 分别处理
try:
    value = int(input("Enter a number: "))
    result = 100 / value
except ValueError:
    print("Invalid input!")
except ZeroDivisionError:
    print("Cannot divide by zero!")

try-except-else-finally

try:
    file = open("data.txt", "r")
    data = file.read()
except FileNotFoundError:
    print("File not found!")
else:
    # 没有异常时执行
    print(f"File content: {data}")
finally:
    # 无论是否异常都执行
    print("Cleanup code here")
    if 'file' in dir() and not file.closed:
        file.close()

自定义异常

class ValidationError(Exception):
    """验证错误基类"""
    pass
 
class InvalidAgeError(ValidationError):
    """年龄无效"""
    def __init__(self, age, message="Age must be between 0 and 150"):
        self.age = age
        self.message = message
        super().__init__(self.message)
 
    def __str__(self):
        return f"{self.message}, got {self.age}"
 
class InvalidEmailError(ValidationError):
    """邮箱无效"""
    pass
 
# 使用
def validate_age(age):
    if not (0 <= age <= 150):
        raise InvalidAgeError(age)
 
try:
    validate_age(200)
except InvalidAgeError as e:
    print(e)

异常最佳实践

# 1. 不要捕获所有异常
# 不好
try:
    do_something()
except:  # 捕获所有,包括SystemExit
    pass
 
# 好
try:
    do_something()
except SpecificException as e:
    handle_error(e)
 
# 2. 使用finally释放资源
# 好
with open("file.txt") as f:
    process(f)
 
# 3. 不要忽略异常
# 不好
try:
    risky_operation()
except Exception:
    pass  # 沉默的异常
 
# 4. 使用raise from保持异常链
try:
    int("not a number")
except ValueError as e:
    raise CustomError("Failed to parse") from e

本章练习

1. 创建自定义异常类层次结构 2. 实现带重试的装饰器 3. 实现上下文管理器处理异常 4. 编写健壮的输入验证函数

下一章:第二十章:模块与包