# GESP等级：四级 | GESP Python 四级考点
"""
==============================================================
14_异常处理 / 第2节_finally综合
    02_知识点_finally结构.py
    时间段: 10:00-30:00  知识点
    ① try-except-finally完整结构
    ② finally不管出不出错都执行
    ③ 应用:关文件/清屏幕
==============================================================
"""

print("=" * 58)
print("📚 知识点一: try-except-finally 完整结构")
print("=" * 58)

# ════════════════════════════════════════════════════════════
# ① try-except-finally 完整结构
# ════════════════════════════════════════════════════════════
# 完整语法格式:
#
#   try:
#       <可能引发异常的代码>
#   except <异常类型> [as 变量]:
#       <异常处理代码>
#   [except ...]               ← 可以有多个 except
#   [else:]                     ← 没有异常时才执行（可选）
#   finally:                    ← 不管有没有异常都执行（必保）
#       <收尾代码>

# ── 标准模板 ──
print("""
┌─────────────────────────────────────────────┐
│  try:                                        │
│      可能出错的代码                           │
│  except ValueError:                          │
│      处理数值错误                             │
│  except (TypeError, ZeroDivisionError) as e:  │
│      处理多种异常                             │
│  else:                                       │
│      没有异常时才执行                         │
│  finally:                                    │
│      不管怎样都要执行的收尾代码               │
└─────────────────────────────────────────────┘
""")

# ── 完整演示: 多except + else + finally ──
def full_structure_demo():
    """展示try-except-else-finally的完整结构。"""
    try:
        a = int(input("请输入被除数: "))
        b = int(input("请输入除数: "))
        result = a / b
    except ValueError:
        print("【except】请输入有效的整数！")
    except ZeroDivisionError:
        print("【except】除数不能为0！")
    else:
        # ★ 只有 try 块没有抛出异常时才会执行 else
        print(f"【else】计算成功: {a} ÷ {b} = {result}")
    finally:
        # ★ 不管前面发生了什么，finally 一定执行
        print("【finally】本次运算结束，收尾工作已完成。")

# ── 运行 ──
# full_structure_demo()


print("\n" + "=" * 58)
print("📚 知识点二: finally不管出不出错都执行")
print("=" * 58)

# ════════════════════════════════════════════════════════════
# ② finally 不管出不出错都执行 —— 四种场景全覆盖
# ════════════════════════════════════════════════════════════

def scenario_normal():
    """场景1: try正常执行 → finally执行"""
    print("── 场景1: try正常执行 ──")
    try:
        print("  try: 一切正常")
    except:
        print("  这里不会执行")
    finally:
        print("  ★ finally: 执行了！(无论try正常与否)")


def scenario_caught():
    """场景2: 异常发生并被except捕获 → finally执行"""
    print("\n── 场景2: 异常被except捕获 ──")
    try:
        print("  try: 准备出错...")
        x = 1 / 0
    except ZeroDivisionError:
        print("  except: 捕获到除零错误")
    finally:
        print("  ★ finally: 执行了！(异常已被处理)")


def scenario_uncaught():
    """场景3: 异常未被except捕获 → finally仍执行（然后程序崩溃）"""
    print("\n── 场景3: 异常未被捕获 ──")
    try:
        print("  try: 准备抛出一个未捕获的异常...")
        # 这里只触发 NameError，而我们只捕获 ValueError
        # 所以异常会向上传播，但 finally 还是会先执行
        unknown_func()          # NameError: name 'unknown_func' is not defined
    except ValueError:
        print("  except: 这个不会执行")
    finally:
        print("  ★ finally: 执行了！(然后程序才崩溃)")
    # 不会执行到这行


def scenario_return():
    """场景4: try/except中有return → finally仍先执行"""
    print("\n── 场景4: return遇到finally ──")

    def test():
        try:
            print("  try: 遇到return马上返回？")
            return "try的返回值"
        finally:
            print("  ★ finally: 不！我先执行！")

    result = test()
    print(f"  返回值: {result}")   # 可以看到 finally 在 return 前执行


# ── 运行四个场景 ──
def run_all_scenarios():
    scenario_normal()
    scenario_caught()
    # scenario_uncaught()   # ← 这会崩溃，取消注释请谨慎
    scenario_return()

run_all_scenarios()

print("""
结论: finally 的"不管怎样"到底有多强？
  ✓ 正常执行 → 执行
  ✓ 异常被捕获 → 执行
  ✓ 异常未被捕获 → 执行（然后程序再崩溃）
  ✓ try/except中有 return → 执行（然后才 return）
  ✓ 甚至 try 里面有 break/continue → 也会先执行 finally
""")


print("\n" + "=" * 58)
print("📚 知识点三: finally的应用场景")
print("=" * 58)

# ════════════════════════════════════════════════════════════
# ③ finally 的典型应用
# ════════════════════════════════════════════════════════════

# ── 应用A: 关闭文件 ──
print("""
【应用A】关闭文件
    文件打开后，无论读写是否成功，都必须关闭。
    finally 是保证文件关闭的最佳选择。

      f = open("data.txt", "r", encoding="utf-8")
      try:
          content = f.read()        # 可能出错
          # ... 处理数据 ...
      except IOError:
          print("文件读写出错！")
      finally:
          f.close()                 # 无论如何都要关闭文件！
""")

def demo_close_file():
    """演示: 用finally保证文件被关闭。"""
    f = None
    try:
        f = open("example.txt", "r", encoding="utf-8")
        print(f.read())
    except FileNotFoundError:
        print("文件不存在，已捕获异常")
    finally:
        if f is not None:
            f.close()
            print("【finally】文件已关闭")
        else:
            print("【finally】文件从未打开，无需关闭")

# ── 运行 ──
# 取消注释运行:
# demo_close_file()


# ── 应用B: 清屏/重置状态 ──
print("""
【应用B】清屏/重置状态
    在图形界面或游戏中，即使操作失败，
    也需要清理临时绘制的内容、重置光标等。
""")

import turtle

def demo_clear_screen():
    """演示: 用finally保证清屏（即使画图失败）。"""
    t = turtle.Turtle()
    t.speed(3)
    try:
        n = int(input("请输入要画的圆的半径: "))
        t.circle(n)                 # 如果n过大或为负，可能超出画布
    except ValueError:
        print("请输入数字！")
    except turtle.TurtleGraphicsError as e:
        print(f"绘图出错: {e}")
    finally:
        # ★ 无论画图成功还是失败，都清理屏幕
        print("【finally】清理屏幕...")
        t.clear()
        t.hideturtle()
        print("【finally】屏幕已清理，程序结束。")
    # 注意: 在真实交互环境中，turtle.bye() 可关闭窗口
    # 这里我们用 clear() 演示"清理"概念


# ── 应用C: 数据库连接（概念预告） ──
print("""
【应用C】数据库连接（后续课程详解）
    conn = connect_to_database()
    try:
        cursor = conn.cursor()
        cursor.execute(sql)
        # ... 业务逻辑 ...
    except DatabaseError:
        print("数据库操作失败")
    finally:
        conn.close()    # 无论成功与否，释放连接
""")

# ── 应用D: 网络请求（概念预告） ──
print("""
【应用D】网络请求释放资源
    response = requests.get(url)
    try:
        data = response.json()
        # ... 数据处理 ...
    except requests.RequestException:
        print("网络请求异常")
    finally:
        response.close()  # 释放连接
""")


print("\n" + "=" * 58)
print("💡 知识点总结")
print("=" * 58)
print("""
┌──────────────────────────────────────────────┐
│  ① 完整结构: try → except → else → finally   │
│  ② finally 永远执行:                          │
│     正常  /  异常被捕获  /  异常未捕获         │
│     return / break / continue 都拦不住它      │
│  ③ 主要应用: 关文件、清屏幕、释放连接等等      │
│  ④ 一句话: finally = 不管怎样都要做的事        │
└──────────────────────────────────────────────┘
""")
