> **GESP等级：四级 | 考级考点：GESP Python 四级**

# 教案：第01节 def动机——定义函数与调用

| 项目 | 内容 |
|------|------|
| 课程名称 | def动机——定义函数与调用 |
| 课程时长 | 60分钟 |
| GESP考点 | #30 函数定义与调用 |
| 前置知识 | turtle模块基本操作、for循环 |
| 核心工具 | Python turtle模块、def关键字 |

---

## 一、教学目标

### 知识与技能
1. 理解"为什么要用函数"——消除重复代码
2. 掌握 def 定义函数的完整语法：`def 函数名():` + 缩进函数体
3. 掌握函数的调用方式：`函数名()`
4. 区分"定义"与"调用"的本质区别

### 过程与方法
- 通过"画正方形"的重复劳动引出def动机
- 通过对比"不用def"与"用def"让学生感受函数的威力
- 通过补全练习和内化记忆钩子巩固语法

### 情感态度价值观
- 培养"偷懒是程序员美德"的意识——消除重复劳动
- 建立"打包思维"——把代码打包成可复用单元
- 感受一次定义、多次调用的成就感

### 记忆钩子（贯穿全课）
> **"def = 写菜谱，调用 = 做菜，光写不调用 = 白写"**

---

## 二、教学过程

### 阶段一：导入——为什么要用def？（00:00-10:00）

#### 1.1 情境引入：画正方形的烦恼（5分钟）

> **老师走上讲台，打开IDLE，新建文件。**
>
> "同学们，我们已经学会用turtle画正方形了，对不对？"
> "画一个边长100的正方形，需要几行代码？"
>
> **（引导学生回答：4行——forward+right循环4次）**

**板书演示（不用def）：**

```python
import turtle
t = turtle.Turtle()

for i in range(4):    # 画一个正方形要4行
    t.forward(100)
    t.right(90)
```

> "很好！那——如果我要画3个正方形呢？"
> "是不是要复制粘贴3次？一共12行！"
> "那如果要画10个正方形呢？40行！"
> "100个呢？400行！！！"
>
> **（语气夸张）** "天哪——这也太累了吧！"

#### 1.2 def登场！（3分钟）

> "有没有办法——把这4行代码**打包**起来，起个名字，以后想画正方形就说一句：'画个正方形！'？"
>
> "有！就是用——**def**！"
> "def = define（定义）——把代码打包成函数！"

**板书对比：**

```
【不用def】                    【用def】
for i in range(4):           def draw_square():       ← 定义一次
    forward(100)                 for i in range(4):
    right(90)                        forward(100)
                                  right(90)
                              
                              draw_square()            ← 随便调用
                              draw_square()            ← 再调用一次
                              draw_square()            ← 再调用一次
```

> "原来要写4行，现在只要写1行！"
> "原来画3个正方形要写12行，现在——定义1次，调用3次，还是1行！"

#### 1.3 首引记忆钩子（2分钟）

> **全班齐读：**
> "**def = 写菜谱**（定义函数，把代码存起来）"
> "**调用 = 做菜**（按照菜谱，真正执行代码）"
> "**光写不调用 = 白写**（只定义不调用，函数不会运行）"

> "记住了吗？每次说到 def，就想到'写菜谱'！"

**GESP考点标注：【#30 函数定义与调用】**

---

### 阶段二：知识点讲解——def的完整语法（10:00-30:00）

#### 2.1 要点①：def 定义函数（5分钟）

**板书：**

```python
def 函数名():       ← def + 函数名 + 小括号 + 冒号
    代码1           ← 缩进的函数体
    代码2
    代码3
```

> **逐词拆解：**
> - `def` —— define的缩写，"我要定义一个函数！"
> - `函数名` —— 给函数取个名字，要**见名知意**（如 draw_square、say_hello）
> - `()` —— 小括号是函数的标志，目前为空（后面学参数再往里填）
> - `:` —— 冒号意味着"接下来是函数的内容"
> - **缩进** —— 函数体必须缩进（统一4个空格），缩进部分才是函数要执行的代码

**身体锚点：** 说 `def` 时右手做"切菜"动作——"打包！"。说 `函数名` 时手指太阳穴——"起名字！"。说 `()` 时双手画圆——"括号标志！"。说 `:` 时右手食指指下方——"准备好了，开始写内容！"

> **错误警示：**
> - ❌ 忘记冒号 → `SyntaxError: expected ':'`
> - ❌ 忘记缩进 → `IndentationError: expected an indented block`
> - ❌ 函数名用中文/数字开头 → `SyntaxError: invalid syntax`

#### 2.2 要点②：调用函数（5分钟）

**板书：**

```python
# 定义（写菜谱）
def say_hello():
    print("你好！")

# 调用（做菜）
say_hello()    # → 输出：你好！
say_hello()    # → 又输出：你好！
```

> **关键对比：**

| 定义 def | 调用 函数名() |
|---------|-------------|
| 写菜谱 | 做菜 |
| 只写一次 | 可以执行无数次 |
| 不会执行代码 | 真正运行代码 |
| 需要 def + 冒号 + 缩进 | 直接写函数名 + 括号 |
| 先定义才能调用 | 调用必须在定义之后 |

> **老师提问：**
> - ❓ "定义函数要不要缩进？"（要！）
> - ❓ "调用函数要不要缩进？"（不要！顶格写）
> - ❓ "先定义还是先调用？"（先定义！菜谱都没写，怎么做菜？）

#### 2.3 执行流程演示（5分钟）

**板书执行流程图：**

```
程序开始运行
     ↓
① 读到 def say_hello():     ← "哦，有个菜谱叫 say_hello，记下来"
②     读到 print("你好！")   ← "这是菜谱的内容，记下来，但不执行"
③ 读到 print("准备调用")     ← "普通代码，执行！" → 输出：准备调用
④ 读到 say_hello()          ← "调用函数！跳到函数体执行！"
                                → 输出：你好！
⑤ 读到 print("调用结束")     ← "函数执行完毕，回到主程序继续"
                                → 输出：调用结束
```

> **关键理解：**
> "def 只是**登记**代码，不是**执行**代码！"
> "只有调用才会真正运行函数体——就像菜谱只是写着步骤，真正做菜才执行步骤。"

**互动环节：** 老师说一段代码，学生用手指指向运行步骤。
- "def draw_square():" → 手指点一下（登记）
- "    for i in range(4):" → 手指点一下（登记）
- "        forward(100)" → 手指点一下（登记）
- "print('开始画')" → 手指跑起来（执行！）
- "draw_square()" → 手指跳到函数体去跑（执行！）

#### 2.4 回顾记忆钩子（2分钟）

> **全班再次齐读：**
> "**def = 写菜谱，调用 = 做菜，光写不调用 = 白写！**"

#### 2.5 完整示例：画正方形（3分钟）

**板书完整示例：**

```python
import turtle

t = turtle.Turtle()

# 第一步：定义函数（写菜谱）
def draw_square():
    for i in range(4):
        t.forward(100)
        t.right(90)

# 第二步：调用函数（做菜）
draw_square()    # 画1个
draw_square()    # 画2个
draw_square()    # 画3个
```

> "同学们注意看——我们只写了一次 for 循环，但画了3个正方形！"
> "这就是 def 的威力——**一次定义，多次使用！**"

**GESP考点标注：【#30 函数定义与调用】**

---

### 阶段三：演示——def draw_square（30:00-40:00）

#### 3.1 打开IDLE，新建文件（2分钟）

> **老师操作，学生同步：**
> 1. 打开 IDLE → File → New File
> 2. 保存为 `第01节_def动机_演示.py`

#### 3.2 无def vs 有def 对比演示（4分钟）

**第一步：不用def——画3个正方形**（老师现场敲代码）

```python
import turtle
t = turtle.Turtle()
t.speed(3)

# 画第1个正方形 —— 4行
for i in range(4):
    t.forward(80)
    t.right(90)

# 画第2个正方形 —— 又4行！复制粘贴！
t.penup()
t.forward(120)
t.pendown()
for i in range(4):
    t.forward(80)
    t.right(90)

# 画第3个正方形 —— 又4行！又复制粘贴！
t.penup()
t.forward(120)
t.pendown()
for i in range(4):
    t.forward(80)
    t.right(90)
```

> "看看——这有多少行？"
> "画1个正方形4行，画3个正方形，不算移动位置都要12行！"

**第二步：用def——画3个正方形**（老师现场敲代码）

```python
import turtle
t = turtle.Turtle()
t.speed(3)

# 定义一次
def draw_square():
    for i in range(4):
        t.forward(80)
        t.right(90)

# 调用3次——每次1行！
draw_square()
t.penup()
t.forward(120)
t.pendown()
draw_square()
t.penup()
t.forward(120)
t.pendown()
draw_square()
```

> "同学们看——正方形代码只写了1次，但画了3个！"
> "如果画100个——还是只写1次！这就是def的魔力！"

#### 3.3 互动提问（2分钟）

> - ❓ "不用def画3个正方形，画正方形的代码要写几遍？"（3遍，每遍4行）
> - ❓ "用def画3个正方形，画正方形的代码要写几遍？"（1遍）
> - ❓ "如果画10个呢？def要写几遍？"（还是1遍！）
> - ❓ "调用 draw_square() 的时候，执行了多少行代码？"（4行——循环体）

#### 3.4 记忆钩子强化（2分钟）

> "还记得吗？def = 写菜谱，调用 = 做菜。"
> "刚才我们——"
> "写了一份菜谱（def draw_square），然后做了3次菜（调用了3次）。"
> "菜谱写一次，菜可以做无数次！"

**GESP考点标注：【#30 函数定义与调用】**

---

### 阶段四：实操练习（40:00-55:00）

#### 4.1 练习一：补全def（5分钟）

**难度：** ⭐

**GESP考点：【#30 函数定义与调用】**

**题目：** 补全下面代码，定义一个画正方形的函数。

```python
____ draw_square():          ← 填空①：关键字
    for i ____ range(4):     ← 填空②：循环关键字
        ____.forward(100)    ← 填空③：海龟对象名
        t.right(90)

# 调用
draw_________()              ← 填空④：调用时写对函数名
```

**空格答案：** ① `def` ② `in` ③ `t` ④ `square`

**教师引导：**
- "定义函数用什么关键字开头？"（def）
- "函数名后面跟着什么？"（小括号 + 冒号）
- "函数体内的代码要怎样？"（缩进）
- "调用函数时写什么？"（函数名 + 小括号）

#### 4.2 练习二：定义并调用draw_triangle（5分钟）

**难度：** ⭐⭐

**GESP考点：【#30 函数定义与调用】**

**题目：** 定义函数 `draw_triangle()` 画一个等边三角形，并调用它。

**等边三角形提示：**
- 循环3次
- 每次 forward(100)
- 每次 left(120) —— 等边三角形外角120度

**参考代码：**

```python
def draw_triangle():
    """画一个等边三角形"""
    for i in range(3):
        t.forward(100)
        t.left(120)

draw_triangle()    # ← 调用
```

**教师引导：**
- ❓ "三角形循环几次？"（3次）
- ❓ "每次转多少度？"（120度——360÷3）
- ❓ "定义好后怎么画这个三角形？"（调用 draw_triangle()）

#### 4.3 练习三：定义draw_star画五角星（5分钟）

**难度：** ⭐⭐⭐

**GESP考点：【#30 函数定义与调用】**

**题目：** 定义函数 `draw_star()` 画一个五角星，并调用它。

**五角星提示：**
- 循环5次
- 每次 forward(150)
- 每次 right(144) —— 五角星转角 = 180 - 180/5 = 144度

**参考代码：**

```python
def draw_star():
    """画一个五角星"""
    for i in range(5):
        t.forward(150)
        t.right(144)

draw_star()    # ← 调用
```

**如果完成得快：** 试着自己再定义一个 draw_hexagon（正六边形）并调用。

#### 4.4 错误案例分析（5分钟）

> **老师演示常见错误，学生找错：**

```
错误①：忘记冒号
    def draw_square()    ← 缺少冒号！
    → SyntaxError: expected ':'

错误②：忘记缩进
    def draw_square():
    for i in range(4):   ← 没有缩进！
    → IndentationError: expected an indented block

错误③：调用时写错函数名
    def draw_square():
        for i in range(4):
            t.forward(100)
            t.right(90)
    drawsquare()         ← 缺少下划线！
    → NameError: name 'drawsquare' is not defined

错误④：只定义不调用
    def draw_square():
        print("画正方形")
    # 没有调用 → 什么都不会输出！
    💡 光写不调用=白写！
```

**记忆钩子：** "def 四个要点——def 关键字、函数名、小括号冒号、缩进不能少！"

**GESP考点标注：【#30 函数定义与调用】**

---

### 阶段五：小测（55:00-60:00）

#### 5.1 核心概念快问快答

| 题号 | 问题 | 答案 | 考点 |
|------|------|------|------|
| 1 | 定义函数用什么关键字？ | def | 【#30】函数定义 |
| 2 | 调用函数怎么写？ | 函数名() | 【#30】函数调用 |
| 3 | 函数体需要什么？ | 缩进（4空格） | 【#30】语法规范 |
| 4 | 函数定义末尾需要什么符号？ | 冒号 : | 【#30】语法规范 |
| 5 | 没有调用函数，函数体会执行吗？ | 不会！ | 【#30】定义vs调用 |
| 6 | 定义1次，可以调用几次？ | 无数次 | 【#30】复用 |
| 7 | def是哪个单词的缩写？ | define（定义） | 【#30】关键字理解 |

#### 5.2 判断对错

> **老师说代码，学生判断是"定义"还是"调用"：**

1. `def draw_square():` → **定义**（有def、有冒号、后面要缩进）
2. `draw_square()` → **调用**（没有def、没有冒号、直接写函数名+括号）
3. `def say_hello(): print("你好")` → **定义**（虽然写在一行，但开头是def）
4. `say_hello()` → **调用**

#### 5.3 预测输出

```python
def say_hi():
    print("你好")

# 没有调用
```
→ ❓ 输出什么？**什么都不输出**（只定义没调用！）

```python
def say_hi():
    print("你好")

say_hi()
say_hi()
```
→ ❓ 输出什么？**两次"你好"**（定义一次，调用两次）

#### 5.4 课堂总结（2分钟）

> **老师带领全班齐读记忆钩子：**
>
> "**def = 写菜谱**（定义函数）"
> "**调用 = 做菜**（运行函数）"
> "**光写不调用 = 白写**（只定义不调用 = 永远不会执行）"
>
> **语法口诀：**
> "**def 函数名加括号，冒号缩进不能少。**
> **调用只需名加括，定义一次用个够！**"
>
> **最后问全班：**
> "为什么我们需要def？"
> **全班答：** "**消除重复代码！一次定义，多次调用！**"

**GESP考点标注：【#30 函数定义与调用】**

---

## 三、板书设计

```
┌─────────────────────────────────────────────────────────┐
│            第01节  def动机——定义函数与调用                │
├─────────────────────────────────────────────────────────┤
│                                                         │
│  一、为什么需要def？                                     │
│      重复代码 → 打包 → 起名字 → 写一次，用无数次        │
│                                                         │
│  二、def语法                                            │
│      def 函数名():           ← def + 名字 + () + :    │
│          代码1               ← 缩进4空格               │
│          代码2                                         │
│                                                         │
│  三、调用                                                │
│      函数名()               ← 直接写名字 + 小括号      │
│                                                         │
│  四、记忆钩子                                            │
│      def = 写菜谱                                        │
│      调用 = 做菜                                         │
│      光写不调用 = 白写                                   │
│                                                         │
│  五、常见错误                                            │
│      ① 忘记冒号  ② 忘记缩进                             │
│      ③ 函数名写错 ④ 只定义不调用                        │
└─────────────────────────────────────────────────────────┘
```

---

## 四、教学准备

1. **硬件：** 电脑（教师机+学生机）、投影仪
2. **软件：** Python 3.x、IDLE 或 VS Code
3. **资料：**
   - 代码文件：`第01节_def动机.py`（教师演示用）
   - 随堂练习：`随堂练习_第01节_def动机.md`
   - 课后练习：`课后练习_第01节_def动机.md`

---

## 五、常见问题与应对

| 问题 | 应对策略 |
|------|---------|
| 学生不理解"为什么要用def" | 用"画100个正方形"的场景夸张化——每次都写4行，写到崩溃！def让4行变1行 |
| 忘记在函数定义末尾写冒号 | 记忆钩子："def 像在说'注意了！'——冒号就是感叹号！" |
| 函数体忘记缩进 | 记忆钩子："函数体是函数的孩子，孩子要缩在爸爸身后（缩进）" |
| 混淆"定义"和"调用" | 用"菜谱 vs 做菜"比喻——菜谱写着步骤（定义），按菜谱做菜（调用） |
| 调用时写了def | "def 只在定义时写一次，调用时只需要函数名+括号！" |
| 函数名写错（下划线/大小写） | "Python不认识'长得差不多'的名字——函数名必须一模一样！" |
| 先调用后定义 | "菜谱都没写，怎么做菜？必须在调用之前先定义！" |
| 认为函数定义时就会执行 | 现场演示：定义一个函数，观察屏幕上没有任何输出——证明定义不执行 |
| 缩进用了Tab混空格 | 统一设置编辑器：Tab = 4个空格。Python 3不允许混用 |
