← 返回主页

第7课: 异常处理

什么是异常?

异常是程序运行时发生的错误。Python提供了异常处理机制来捕获和处理这些错误,避免程序崩溃。

常见异常类型

try-except语句

使用try-except捕获和处理异常。

基本用法

try:
    result = 10 / 0
except ZeroDivisionError:
    print("错误:不能除以零!")

print("程序继续运行")

捕获多个异常

try:
    num = int(input("请输入一个数字: "))
    result = 100 / num
    print(f"结果: {result}")
except ValueError:
    print("错误:请输入有效的数字")
except ZeroDivisionError:
    print("错误:不能除以零")
except Exception as e:
    print(f"发生未知错误: {e}")

捕获多个异常(简化写法)

try:
    # 可能出错的代码
    value = int("abc")
except (ValueError, TypeError) as e:
    print(f"输入错误: {e}")

try-except-else-finally

try:
    file = open("data.txt", "r")
    content = file.read()
except FileNotFoundError:
    print("文件不存在")
else:
    # 没有异常时执行
    print("文件读取成功")
    print(content)
finally:
    # 无论是否有异常都会执行
    print("清理资源")
    if 'file' in locals():
        file.close()

抛出异常

使用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}")

重新抛出异常

def process_data(data):
    try:
        result = int(data)
        return result
    except ValueError:
        print("数据格式错误,重新抛出异常")
        raise  # 重新抛出当前异常

try:
    process_data("abc")
except ValueError:
    print("在外层捕获异常")

自定义异常

创建自定义异常类来处理特定的错误情况。

class AgeError(Exception):
    def __init__(self, age, message="年龄不合法"):
        self.age = age
        self.message = message
        super().__init__(self.message)

def check_age(age):
    if age < 0:
        raise AgeError(age, "年龄不能为负数")
    elif age > 150:
        raise AgeError(age, "年龄不能超过150岁")
    else:
        print(f"年龄{age}岁,合法")

try:
    check_age(-5)
except AgeError as e:
    print(f"错误: {e.message},输入的年龄是{e.age}")

断言 (assert)

断言用于调试,检查条件是否为真。

def calculate_average(numbers):
    assert len(numbers) > 0, "列表不能为空"
    return sum(numbers) / len(numbers)

try:
    avg = calculate_average([])
except AssertionError as e:
    print(f"断言错误: {e}")

# 正常情况
avg = calculate_average([85, 90, 88])
print(f"平均分: {avg}")

上下文管理器 (with语句)

with语句自动处理资源的获取和释放。

# 传统方式
try:
    file = open("data.txt", "r")
    content = file.read()
finally:
    file.close()

# 使用with语句(推荐)
with open("data.txt", "r") as file:
    content = file.read()
# 文件自动关闭,无需手动调用close()

自定义上下文管理器

class DatabaseConnection:
    def __enter__(self):
        print("打开数据库连接")
        return self

    def __exit__(self, exc_type, exc_val, exc_tb):
        print("关闭数据库连接")
        return False

    def query(self, sql):
        print(f"执行SQL: {sql}")

with DatabaseConnection() as db:
    db.query("SELECT * FROM users")

异常处理最佳实践

# 不好的做法
try:
    # 代码
    pass
except:  # 捕获所有异常
    pass  # 忽略所有错误

# 好的做法
import logging

try:
    result = risky_operation()
except ValueError as e:
    logging.error(f"值错误: {e}")
    # 处理错误
except Exception as e:
    logging.error(f"未预期的错误: {e}")
    raise  # 重新抛出

练习

  1. 编写程序,要求用户输入两个数字并计算除法,处理所有可能的异常
  2. 创建一个函数读取文件内容,使用异常处理处理文件不存在的情况
  3. 自定义一个PasswordError异常,验证密码长度必须大于8位
  4. 使用with语句写入文件,确保文件正确关闭
练习答案:
# 练习1:安全除法
def safe_divide():
    try:
        a = float(input("输入第一个数: "))
        b = float(input("输入第二个数: "))
        result = a / b
        print(f"结果: {result}")
    except ValueError:
        print("错误:请输入有效数字")
    except ZeroDivisionError:
        print("错误:除数不能为零")
    except Exception as e:
        print(f"未知错误: {e}")

# 练习2:读取文件
def read_file(filename):
    try:
        with open(filename, 'r', encoding='utf-8') as f:
            return f.read()
    except FileNotFoundError:
        print(f"文件{filename}不存在")
        return None

# 练习3:密码验证
class PasswordError(Exception):
    pass

def validate_password(password):
    if len(password) < 8:
        raise PasswordError("密码长度必须大于8位")
    print("密码有效")

try:
    validate_password("123")
except PasswordError as e:
    print(f"错误: {e}")

# 练习4:写入文件
try:
    with open("output.txt", "w", encoding="utf-8") as f:
        f.write("Hello, Python!")
    print("文件写入成功")
except IOError as e:
    print(f"文件写入失败: {e}")