# GESP等级：四级 | GESP Python 四级考点
"""
==============================================================
14_异常处理 / 第2节_finally综合
    01_导入_finally.py
    时间段: 00:00-10:00  导入 —— "不管出不出错都要执行→finally"
==============================================================

记忆钩子:
    finally = 不管怎样都要做的事

生活中的"不管怎样都要做":
    - 无论考试及格还是不及格，都要交卷  →  finally
    - 无论文件有没有找到，都要归还钥匙  →  finally
    - 无论代码是否报错，finally块始终执行

本节目录:
    1. 常规代码的问题 —— 没有finally
    2. finally登场 —— 保证收尾
    3. 初步对比
"""

# ════════════════════════════════════════════════════════════════
# 1. 常规代码的问题 —— 没有finally
# ════════════════════════════════════════════════════════════════
# 场景: 用户输入一个数字，程序用 turtle 画圆。
# 如果用户输入的不是数字，程序崩溃，无法执行"程序结束"的提示。

# 问题示例（仅用于理解思路，先不运行）:
#   n = int(input("请输入一个数字: "))   # 如果输入"abc" → 崩溃
#   print("程序结束")                     # 这行根本没机会执行

# 结论: 当 try 块内某行报错，后续代码会直接跳过，
#       "收尾工作"无法保证执行。

print("=" * 55)
print("【问题】没有finally，出错时收尾代码无法执行")
print("=" * 55)

def demo_without_finally():
    """演示: 没有finally时，异常发生后收尾代码被跳过。"""
    try:
        n = int(input("请输入一个数字: "))       # ← 可能报错
        print(f"你输入的数字是: {n}")
    except ValueError:
        print("【捕获】输入的不是数字，已处理异常")

    # 下面的代码在 except 之后会执行（因为异常被处理了），
    # 但如果异常没被捕获（比如 KeyboardInterrupt）则不会执行。
    # 更重要的是 —— 我们想表达: 无论 try/except 结果如何，
    # 某些代码必须执行。下面这行并不能保证"无论如何都执行"。
    print("程序结束（不一定能执行到哦）")

# ── 运行 ──
# 取消下一行的注释来运行:
# demo_without_finally()


# ════════════════════════════════════════════════════════════════
# 2. finally登场 —— 保证收尾
# ════════════════════════════════════════════════════════════════
# try-except-finally 完整语法:

#   try:
#       可能出错的代码
#   except 异常类型:
#       处理异常的代码
#   finally:
#       不管出不出错都执行的代码    ← 这就是finally!

# finally 的特点:
#   - try 块正常执行完毕 → finally 执行
#   - try 块抛出异常，被 except 捕获 → finally 执行
#   - try 块抛出异常，没有被 except 捕获 → finally 仍执行（然后程序才崩溃）
#   - 即使 try/except 中有 return，finally 也会在 return 之前执行!

print("\n" + "=" * 55)
print("【方案】用finally保证收尾代码无论如何都执行")
print("=" * 55)

def demo_with_finally():
    """演示: 使用finally保证收尾代码一定执行。"""
    try:
        n = int(input("请输入一个数字: "))
        print(f"你输入的数字是: {n}")
    except ValueError:
        print("【捕获】输入的不是数字，已处理异常")
    finally:
        # ★ 不管 try 是否出错，不管 except 是否执行，这里永远执行
        print("【finally】程序结束 —— 我无论如何都会执行！")

# ── 运行 ──
# 取消下一行的注释来运行:
# demo_with_finally()


# ════════════════════════════════════════════════════════════════
# 3. 初步对比
# ════════════════════════════════════════════════════════════════
print("\n" + "=" * 55)
print("【对比】有无finally的关键区别")
print("=" * 55)

comparison = """
┌─────────────────────┬─────────────────────────────────┬──────────────────────────────┐
│     场景            │  没有finally                    │  有finally                   │
├─────────────────────┼─────────────────────────────────┼──────────────────────────────┤
│ try正常执行         │ 收尾代码执行                    │ 收尾代码执行                 │
│ except处理异常      │ 收尾代码执行                    │ 收尾代码执行                 │
│ 未捕获的异常        │ 收尾代码被跳过 → 程序崩溃      │ 收尾代码仍执行 → 然后再崩溃  │
│ try/except中有return│ 收尾代码被跳过                  │ finally先执行,再return        │
└─────────────────────┴─────────────────────────────────┴──────────────────────────────┘
"""
print(comparison)

print("一句话总结: finally = 不管怎样都要做的事")

# ── 思考题（先不用运行，想一下答案）──
print("思考: 假如你在写一个文件，打开后突然报错了，")
print("      文件没有关闭会有什么后果？")
print("      下一节我们会学到: finally 正好用来关文件！")
