第十七课:当程序遇到“意外” – 错误处理 (try…except)

  • 时长: 90 分钟
  • 教学目标:
    • 理解程序在运行过程中可能遇到的各种“意外”或“错误”。
    • 区分简单的语法错误和运行中出现的错误(异常)。
    • 学习 try...except 结构:一种“尝试”执行代码,并在出错时“捕捉”并处理错误的方法。
    • 理解 try...except 的执行流程:先尝试 try 里面的代码,如果出错就跳到 except 块执行,没出错就跳过 except 块。
    • 学习如何“捕捉”特定类型的错误(比如用户输入了错误的类型,或者文件不存在)。
    • 知道如何获取并打印错误的具体信息。
    • 理解错误处理让程序更稳定、更友好。

课程内容

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

  • 复习: 快速回顾文件操作(open, read, write, with open)。 提及我们之前在文件操作中可能遇到的问题,比如读取一个不存在的文件会报错。
  • 提出问题: 老师提问:“你们在写代码或者运行别人的程序时,有没有遇到过程序突然停下来,屏幕上打印一大堆红色的错误信息的情况?这说明程序‘崩溃’了,没有按我们预想的完成任务。比如,如果我们让用户输入一个数字,用户却输入了一段文字,程序就会报错停下来。”
  • 引出错误处理: 正常的程序应该能预料到一些可能的“意外”,并在发生意外时,不是直接崩溃,而是优雅地处理它,比如给用户一个提示,或者记录下来问题,然后继续运行。这就是错误处理

2. 认识程序的“错误”和“意外” (10 分钟)

  • 语法错误 (Syntax Error): 这是最常见的错误,通常是你的代码写错了,不符合 Python 的语法规则,比如少了个冒号,引号没配对,函数名写错了等等。这种错误在程序运行之前(或者运行刚开始时)就会被 Python 检查出来,程序根本不会开始执行或者只会执行一部分。IDE 通常会提前提示这些错误。
    # 这是一个语法错误:if 后面少了冒号
    # if True
    #     print("这会出错")
    
  • 运行时错误 / 异常 (Runtime Error / Exception): 代码语法本身可能是对的,但是在程序运行的时候,因为某些原因(比如用户输入了不对的数据,要打开的文件不存在,数字除以了零),导致程序无法继续执行下去。这种错误叫做异常
    # 这是一个运行时错误:用户输入了非数字,int() 转换会失败
    # age_str = input("请输入年龄:") # 如果用户输入 "abc"
    # age = int(age_str) # 这行就会引发 ValueError 异常
    
    # 这是一个运行时错误:尝试除以零
    # result = 10 / 0 # 这行会引发 ZeroDivisionError 异常
    
    # 这是一个运行时错误:尝试打开不存在的文件
    # file = open("non_exist.txt", "r") # 这行会引发 FileNotFoundError 异常
    
  • 本节课重点: 我们主要学习如何处理运行时错误(异常),让程序在遇到这些意外时,可以继续运行下去。

3. 尝试做,万一错了就这样办 – try…except (15 分钟)

  • 核心思想: try...except 结构就像一个“尝试”和“备用方案”。我们把可能会出错的代码放在 try 代码块里“尝试”执行。如果 try 块里的代码没有出错,except 块就会被跳过,程序继续往下执行。如果 try 块里的代码发生错误,Python 就会立即停止执行 try 块中出错的那一行以及后面的代码,然后跳到 except 代码块里执行“备用方案”的代码。
  • 语法:
    try:
        # 尝试执行的代码 (可能出错的代码)
        print("尝试执行代码...")
        # ... 可能引发错误的代码 ...
        print("尝试代码执行成功!") # 如果上面的代码没出错,这行会执行
    except:
        # 如果 try 块里的代码出错了,就执行这里的代码 (错误处理代码)
        print("出错了!执行备用方案。")
        # ... 处理错误的代码 ...
    
    # 无论 try 块是否出错,except 块是否执行,try...except 结构后面的代码都会继续执行
    print("程序继续运行。")
    
  • 演示: 演示一个没有错误处理的代码,当出错时程序停止。 然后用 try...except 包围起来,演示出错时程序不会崩溃,而是执行 except 块的内容。
    print("--- 没有错误处理 ---")
    # print(10 / 0) # 运行到这里会崩溃
    print("这行不会被打印") # 如果上面崩溃,这行就不会执行
    
    print("\n--- 使用 try...except ---")
    try:
        print("正在尝试除以零...")
        result = 10 / 0 # 这行会出错
        print("结果是:", result) # 这行不会执行
    except:
        print("呀!除法出错了,不能除以零!")
    
    print("程序继续运行,没有崩溃!")
    
  • 动手实践: 学生编写代码,故意写一个会引发错误的语句(比如访问列表不存在的索引 [1, 2][5]),不加 try...except 运行看崩溃。 然后用 try...except 包围起来,让程序在出错时打印一条友好的提示信息。

4. 捕捉特定类型的错误 (20 分钟)

  • 问题: 前面的 except 语句会捕捉任何类型的错误。但我们通常想针对不同的错误做不同的处理,比如输入类型错误和文件不存在是不同的问题。
  • 捕捉特定错误: 可以在 except 后面指定想捕捉的错误类型。
  • 语法: except 错误类型:except 错误类型 as 变量名:
    try:
        age_str = input("请输入年龄:") # 可能引发 ValueError
        age = int(age_str)
        print("你的年龄是:", age)
    
        file_name = input("请输入要打开的文件名:") # 可能引发 FileNotFoundError
        with open(file_name, 'r') as f:
            content = f.read()
            print("文件内容:\n", content)
    
        result = 100 / age # 如果 age 是 0,可能引发 ZeroDivisionError
        print("100 除以年龄的结果:", result)
    
    except ValueError: # 捕捉 ValueError 类型的错误
        print("错误:请输入一个有效的整数年龄!")
    except FileNotFoundError: # 捕捉 FileNotFoundError 类型的错误
        print("错误:找不到指定的文件!")
    except ZeroDivisionError: # 捕捉 ZeroDivisionError 类型的错误
        print("错误:年龄不能是零,不能进行除法运算!")
    except Exception as e: # 捕捉所有其他类型的错误,并将错误信息存到变量 e 中
        print("发生了未知错误:", e)
    
    print("程序继续执行。")
    
  • 重要: 可以有多个 except 块,程序会从上往下匹配错误类型,执行第一个匹配到的 except 块。最后的 except Exception as e: 可以用来捕捉所有你没有明确指定的错误,防止程序崩溃。 Exception 是所有内置错误类型的老祖宗。
  • 获取错误信息: 使用 as 变量名 可以把错误对象存到一个变量里,通常叫做 eerr。打印这个变量可以得到错误的具体描述信息。
  • 动手实践: 学生编写代码,包含用户输入转换为数字、除法运算等可能出错的操作。 使用多个 except 块分别捕捉 ValueErrorZeroDivisionError,并打印不同的错误提示信息。 尝试输入文字和输入 0,看程序输出。

5. 课堂练习 (20 分钟)

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

  • 练习 1: 编写一个程序,询问用户输入两个数字,计算它们的除法结果并打印。使用 try...except 处理可能出现的 ValueError (输入的不是数字) 和 ZeroDivisionError (除数为零)。
    # 在这里写你的代码
    try:
        num1_str = input("请输入第一个数字:")
        num1 = float(num1_str)
    
        num2_str = input("请输入第二个数字:")
        num2 = float(num2_str)
    
        # TODO: 计算 num1 / num2
        # TODO: 打印结果
    
    except ValueError:
        # TODO: 打印处理 ValueError 的信息
        pass
    except ZeroDivisionError:
        # TODO: 打印处理 ZeroDivisionError 的信息
        pass
    
    print("程序运行结束。")
    
  • 练习 2: 编写一个程序,要求用户输入文件名,并尝试以读取模式 ('r') 打开该文件,读取内容并打印。使用 try...except FileNotFoundError 处理文件不存在的情况,打印友好的提示。
  • 练习 3: 编写一个程序,创建一个列表 my_list = ["apple", "banana"]。要求用户输入一个索引(整数),尝试打印列表中该索引位置的元素。使用 try...except IndexError 处理用户输入的索引超出列表范围的情况。使用 try...except ValueError 处理用户输入的不是有效整数的情况。

6. 总结与提问 (10 分钟)

  • 回顾: 回顾本节课内容:程序中的错误和异常,try...except 结构的作用(尝试执行,捕捉错误),如何捕捉特定类型的错误,except Exception as e: 的作用,如何获取错误信息,错误处理让程序更稳定。
  • 提问:
    • 语法错误和运行时错误有什么区别?
    • try 块里的代码有什么特点?
    • try 块里的代码出错时,程序会做什么?
    • except ValueError: 是用来捕捉什么错误?
    • except:except 错误类型: 有什么不同?
    • 为什么要进行错误处理?
  • 答疑: 回答学生问题。

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

  • 作业 1: 编写一个程序,要求用户输入一个整数。使用 try...except 结构,如果用户输入的是非整数,就打印“输入无效,请重新运行并输入整数!” 程序不会因为输入错误而崩溃。
  • 作业 2: 编写一个程序,尝试从一个叫做 settings.txt 的文件中读取第一行内容并打印。使用 try...except FileNotFoundError 处理文件不存在的情况,如果文件不存在,就打印“设置文件找不到,将使用默认设置。”
  • 作业 3: (选做) 编写一个程序,使用 while True 循环和 try...except 结构,不断要求用户输入一个有效的整数。只有当用户输入了有效的整数后,才退出循环并打印这个整数。如果输入无效,打印提示信息,然后继续循环要求输入。

声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。