• 时长: 90 分钟
  • 教学目标:
    • 复习 try...except 语句的基本用法和作用。
    • 深入理解如何捕获多个不同类型的错误,并分别进行处理。
    • 学习在 except 块中如何获取并打印详细的错误信息。
    • 掌握 finally 语句的用法:无论 try 块中是否发生错误,finally 块中的代码都一定会执行。
    • 理解 finally 在资源清理(如文件关闭、数据库连接释放)中的重要作用。
    • 能够编写更健壮的代码,有效处理程序运行时可能发生的多种异常情况。

课程内容

1. 复习与引入 (10 分钟)

  • 复习: 快速回顾上一节综合项目中 try-except 的应用(例如处理用户输入无效、文件找不到等)。
  • 提出问题: 老师提问:“我们之前用 try-except 让程序在遇到错误时不会崩溃,而是打印一个提示。但有时候,一个代码块可能会引发好几种不同的错误,比如用户输入非数字,或者除数为零。我们怎么针对不同的错误给出不同的提示呢?另外,不管程序有没有出错,总有一些收尾工作(比如关闭文件、保存数据)是必须做的,有没有办法保证这些代码一定会被执行?”
  • 引出新知识: 今天我们将学习如何更精确地捕获和处理不同类型的错误,以及一个非常重要的 finally 语句,它能确保某些代码无论如何都会被执行,这对于程序的稳定性至关重要。

2. 捕获多种类型的错误 (20 分钟)

  • 回顾基本捕获: try...except: (捕获所有错误)或 try...except 错误类型: (捕获特定错误)。
  • 捕获多个特定错误: 可以写多个 except 块,每个块捕获一种特定的错误类型。
    print("--- 捕获多种错误示例 ---")
    try:
        user_input = input("请输入一个数字(不要输入0):")
        num = int(user_input) # 可能引发 ValueError
    
        result = 100 / num # 可能引发 ZeroDivisionError
    
        my_list = [10, 20]
        print(my_list[5]) # 可能引发 IndexError
    
        print("计算结果:", result)
    except ValueError:
        print("错误:您输入的内容不是有效的整数!")
    except ZeroDivisionError:
        print("错误:除数不能为零!")
    except IndexError:
        print("错误:列表索引超出了范围!")
    # 也可以在最后放一个通用的 Exception 来捕获所有未被上面捕获的错误
    except Exception as e:
        print(f"发生了一个未知错误: {e}")
    
    print("程序继续执行。")
    
  • 将多种错误类型放在一个 except 中: 如果对多种错误的处理方式相同,可以将它们放在一个元组里,用一个 except 块捕获。
    print("--- 捕获多种错误类型(合并处理)示例 ---")
    try:
        data = {"name": "Alice"}
        print(data["age"]) # KeyError
        # result = 10 / 0 # ZeroDivisionError
    except (KeyError, ZeroDivisionError) as e: # 同时捕获 KeyError 和 ZeroDivisionError
        print(f"发生了数据访问或数学计算错误: {e}")
    except ValueError as e:
        print(f"发生了值转换错误: {e}")
    except Exception as e:
        print(f"发生了其他未知的错误: {e}")
    
    print("程序继续执行。")
    
  • 使用 as e 获取错误对象:except 错误类型 as 变量名: 中,变量名 会得到一个错误对象,里面包含了错误的详细信息,打印它会非常有帮助。
    try:
        name = "Bob"
        # 故意制造一个错误:尝试对字符串求平方根 (TypeError)
        print(math.sqrt(name))
    except TypeError as err: # 将错误对象存入 err 变量
        print(f"错误类型: {type(err)}")
        print(f"错误信息: {err}") # 打印错误信息
    
  • 动手实践: 学生编写一个程序,尝试从一个字典中获取用户输入的键的值。用 try-except 捕获 KeyError(键不存在)和 TypeError(如果用户输入的键类型不对),并分别打印不同的提示信息。

3. 无论如何都要执行 – finally 语句 (25 分钟)

  • 概念: finally 块是 try-except 结构的一部分。无论 try 块中的代码是否发生错误,finally 块中的代码都一定会执行
  • 语法:
    try:
        # 可能会出错的代码
        print("尝试执行 try 块。")
        # result = 1 / 0 # 这里如果出错
        print("try 块中的其他代码。")
    except ZeroDivisionError:
        # 如果 try 块出错,且是 ZeroDivisionError,就执行这里
        print("进入 except 块处理错误。")
    finally:
        # 无论 try 块是否出错,也无论 except 块是否执行,这里都会执行
        print("进入 finally 块,这是最后一定会执行的代码。")
    print("程序继续执行 after try-except-finally。")
    
  • finally 的作用场景 (重点!): finally 最常用于清理资源,确保一些重要的操作(比如文件关闭、网络连接断开、数据库连接释放)无论程序是否正常运行都能被执行。
  • 文件操作中的 finally (旧式用法,与 with 对比): 之前我们学了 with open() 可以自动关闭文件,这很方便。但如果不用 with,手动打开文件时,finally 就非常重要了。
    # 示例:文件操作中 finally 的应用 (不推荐直接使用,但为了理解 finally 很有用)
    file_obj = None # 确保 file_obj 变量在 try 外部定义,否则 except 或 finally 访问不到
    try:
        file_obj = open("my_test_file.txt", "r") # 假设文件存在,可能引发 FileNotFoundError
        content = file_obj.read()
        print("文件内容:", content)
        # 模拟一个其他错误,导致文件没有被及时关闭
        # data = 1 / 0
    except FileNotFoundError:
        print("错误:文件不存在!")
    except Exception as e: # 捕获其他所有错误
        print(f"读取文件时发生其他错误: {e}")
    finally:
        # 无论上面是否出错,只要 file_obj 被成功赋值,就尝试关闭它
        if file_obj: # 检查 file_obj 是否已经被成功打开 (不为 None)
            file_obj.close()
            print("文件已在 finally 块中关闭。")
        else:
            print("文件未成功打开,无需关闭。")
    
    print("程序结束。")
    
  • with open() 对比: with open() 语句内部其实就是利用了 try-finally 的机制来实现文件的自动关闭,所以我们更推荐使用 with open() 来操作文件。但 finally 的概念在其他需要资源清理的场景中仍然非常重要。
  • 动手实践: 学生编写一个程序,包含 try, exceptfinally。在 try 块中尝试制造一个错误(例如除零),观察 finally 块是否执行。 然后移除错误,再次观察 finally 块是否依然执行。

4. 课堂练习 (15 分钟)

让学生独立完成以下练习:

  • 练习 1: 编写一个程序,让用户输入一个字符串和一个整数索引。尝试从字符串中获取对应索引的字符并打印。使用 try-except IndexError 捕获索引超出范围的错误,并使用 try-except ValueError 捕获用户输入索引不是整数的错误。
    my_string = "Python编程"
    # TODO: 获取用户输入的索引 (字符串)
    # TODO: 使用 try 块转换索引为整数,并访问字符串字符
    # TODO: 编写 except ValueError 处理非整数输入
    # TODO: 编写 except IndexError 处理索引越界
    
  • 练习 2: 编写一个程序,让用户输入两个数字。尝试进行除法运算并打印结果。要求:
    • 如果用户输入非数字,打印“输入无效,请确保都是数字。”
    • 如果除数为零,打印“除数不能为零。”
    • 无论除法是否成功,最后都打印一句“计算尝试完毕。”(使用 finally)。
  • 练习 3: (选做) 编写一个函数 read_and_process_file(filename),接收文件名作为参数。
    • 在函数内部使用 try-except FileNotFoundError 捕获文件不存在的错误。
    • try 块中打开文件(可以使用 with open() 更简洁),读取所有行。
    • 尝试将每行内容转换为整数并求和(这里可能会有 ValueError)。
    • 使用另一个 except ValueError 块来捕获转换错误,并打印“文件中包含无效的数字行”。
    • 无论文件是否成功处理,最后都打印一句“文件处理完成。”(使用 finally)。

5. 总结与提问 (5 分钟)

  • 回顾: 回顾本节课内容:捕获多种错误类型的方法(多个 except 块,或用元组合并),as e 获取错误信息,finally 语句的特点(无论是否出错都执行),以及 finally 在资源清理中的重要作用。
  • 提问:
    • 一个 try 块后面可以跟几个 except 块?
    • except (ValueError, TypeError): 这种写法有什么好处?
    • finally 块里的代码什么时候会执行?
    • 在文件操作中,finallywith open() 有什么共同的优点?
  • 答疑: 回答学生问题。

6. 布置课后作业 (5 分钟)

  • 作业 1: 编写一个函数 get_user_age(),循环让用户输入年龄,直到用户输入一个有效的正整数为止。在函数内部使用 try-except ValueErrorwhile True 循环,并在成功获取年龄后 return 年龄。如果年龄不是正数,也要提示错误。
  • 作业 2: 编写一个程序,尝试打开一个名为 log.txt 的文件,以追加模式写入一条日志信息“程序启动时间:[当前时间]”(使用 datetime 模块获取当前时间)。无论写入是否成功,最后都打印“日志写入尝试结束。”(使用 finally)。
  • 作业 3: (选做) 编写一个简单的学生成绩查询系统(命令行版)。
    • 创建一个学生成绩字典,例如 {"小明": 90, "小红": 85, "小刚": 78}
    • 让用户循环输入学生姓名,如果学生姓名在字典中,打印分数;如果不在,提示“该学生不存在”。
    • 使用 try-except 捕获 KeyboardInterrupt 错误(当用户按 Ctrl+C 退出程序时会发生),并在捕获到此错误时,打印“程序被中断,再见!”然后退出循环。
  1. 本网站名称:系统驰云
  2. 本站永久网址:https://blog.xxyyo.com
  3. 本网站的内容均来源于网络,仅供大家学习与交流,如有侵权,请联系站长365919529@qq.com删除处理。
  4. 本站一切资源不代表本站立场,并不代表本站赞同其观点和对其真实性负责。
  5. 本站一律禁止以任何方式发布或转载任何违法的相关信息,访客发现请向站长举报
  6. 本站资源大多存储在云盘,如发现链接失效,请联系我们我们会第一时间更新。365919529@qq.com