> **GESP等级：四级 | 考级考点：GESP Python 四级**

# 教师参考答案 — 第3节 参数进阶

---

## 一、教案核心要点

### GESP考点对照

| GESP考点 | 知识点 | 示例 |
|---------|--------|------|
| #函数参数传递 | 位置参数 | `def f(a, b): f(1, 2)` |
| #函数参数传递 | 关键字参数 | `f(b=2, a=1)` |
| #函数参数传递 | 默认参数 | `def f(a, b=10): f(1)` |
| #函数参数传递 | *args多参数 | `def f(*args): f(1,2,3)` |

### 记忆钩子（建议课堂反复强调）

```
位置按顺序    → 排队取餐，先来后到
关键字按名字  → 叫名字领东西
默认有默认值  → 师傅默认加葱
多参数收所有  → *args 像收容所，什么都要
```

---

## 二、主演示代码运行结果

### `11第3节4_代码.py` 运行预期结果

#### 导入环节
```
============================================================
【导入】函数参数有几种写法？—— 位置/关键字/默认值
============================================================

前面学了 def 定义函数，但参数只能硬写吗？

看这句：
  def greet(name):          # name 是'位置参数'
      print(f'你好，{name}！')

调用时：
  greet('小明')             # 必须按顺序传一个值

其实，函数参数有 4 种写法：
 ① 位置参数   →  按顺序传值
 ② 关键字参数  →  按名字传值（name=value）
 ③ 默认参数   →  定义时给默认值（不传就用默认）
 ④ *args多参数 →  收一堆值打包成元组
```

#### 知识点 — 位置参数演示
```
① 位置参数（Positional Arguments）—— 按顺序
--------------------------------------------------
  语法： def func(参数1, 参数2, ...)
  特点：
    • 调用时按定义时的顺序传值
    • 顺序错了，结果就错了
    • 最基础、最常用的传参方式

  def introduce(name, age, city):
      print(f'大家好，我叫{name}，今年{age}岁，来自{city}。')

  正确顺序调用：
  大家好，我叫小明，今年10岁，来自北京。

  错误顺序调用（顺序反了）：
  大家好，我叫北京，今年10岁，来自小明。
  （虽然不报错，但意思完全变了！）
```

#### 知识点 — 关键字参数演示
```
② 关键字参数（Keyword Arguments）—— 按名字
--------------------------------------------------
  def show_student(name, score, subject):
      print(f'学生：{name}，{subject}成绩：{score}分')

  # 关键字参数调用（顺序打乱也不怕）：
  学生：小红，数学成绩：95分

  对比位置参数：
  show_student('小红', 95, '数学')  # 必须按顺序
  学生：小红，数学成绩：95分

  关键字参数的好处：
  ✓ 不用记参数的顺序
  ✓ 代码可读性更高
  ✓ 可以只传部分参数（配合默认参数）
```

#### 知识点 — 默认参数演示
```
③ 默认参数（Default Arguments）—— 有默认值
--------------------------------------------------
  def greet(name, greeting='你好'):

  # 不传 greeting → 用默认值'你好'
  你好，小明！

  # 传了 greeting → 用传入的值
  Hello，小红！
  嗨，小刚！
```

#### 知识点 — *args 多参数演示
```
④ *args — 多参数（收一堆值）
--------------------------------------------------
  def sum_all(*args):

  # 可以传任意数量的参数：
  传入的参数：(1, 2, 3)
  求和结果：6

  传入的参数：(10, 20, 30, 40, 50)
  求和结果：150

  传入的参数：(5,)
  求和结果：5

  传入的参数：()
  求和结果：0
```

---

## 三、实操代码答案

### 实操①：位置 vs 关键字参数填空

**题目1：** name 是**位置**参数，age 是**默认**参数

**题目2：**
```python
result = calc(a=3, b=2, c=1)   # → 输出 41
```

**题目3：** `func(1, c=5, 2)` 会报错 `SyntaxError: positional argument follows keyword argument`
正确写法：`func(1, 2, c=5)` 或 `func(a=1, b=2, c=5)`

### 实操②：用默认参数简化函数调用

```python
def make_drink(name, temperature="常温", sugar=True, ice=False, cup_size="中"):
    desc = f"【{cup_size}杯】{temperature}{name}，"
    desc += f"{'加糖' if sugar else '无糖'}，"
    desc += f"{'加冰' if ice else '去冰'}"
    print(f"  制作：{desc}")
    return desc
```

调用结果：
```
make_drink("奶茶")
→ 制作：【中杯】常温奶茶，加糖，去冰

make_drink("柠檬茶", temperature="冰")
→ 制作：【中杯】冰柠檬茶，加糖，去冰

make_drink("咖啡", sugar=False, cup_size="小")
→ 制作：【小杯】常温咖啡，无糖，去冰

make_drink("果茶", temperature="热", cup_size="大")
→ 制作：【大杯】热果茶，加糖，去冰
```

### 实操③：补全多参数代码

**题目1：**
```python
def average(*args):
    """计算传入所有数字的平均值"""
    if len(args) == 0:
        return 0
    total = sum(args)
    return total / len(args)

# 运行结果
average(10, 20, 30)        → 20.0
average(5, 15, 25, 35, 45) → 25.0
average()                  → 0
```

**题目2：**
```python
def print_all(*items, prefix=">> "):
    for item in items:
        print(f"  {prefix}{item}")

# 运行结果
print_all("苹果", "香蕉", "橘子")
→   >> 苹果
→   >> 香蕉
→   >> 橘子

print_all(1, 2, 3, 4, 5, prefix="# ")
→   # 1
→   # 2
→   # 3
→   # 4
→   # 5
```

**题目3：**
```python
def make_menu(restaurant, *dishes):
    print(f"  【{restaurant}】菜单：")
    for i, dish in enumerate(dishes, 1):
        print(f"    {i}. {dish}")

# 运行结果
make_menu("川菜馆", "回锅肉", "麻婆豆腐", "水煮鱼")
→   【川菜馆】菜单：
→     1. 回锅肉
→     2. 麻婆豆腐
→     3. 水煮鱼

make_menu("甜品店", "蛋糕", "奶茶")
→   【甜品店】菜单：
→     1. 蛋糕
→     2. 奶茶
```

---

## 四、课堂练习册答案

### 练习一：参数类型连线

| 调用方式 | 参数类型 |
|---------|---------|
| `func(1, 2, 3)` | 位置参数 |
| `func(a=1, b=2)` | 关键字参数 |
| `func(1, 2, c=3)` | 混合使用（位置+关键字） |
| `def func(a, b=10)` 中 b=10 | 默认参数 |
| `func(*args)` 中的 *args | 多参数（*args） |

### 练习二：看代码写结果

**题目1：**
```
你好，小明！
Hello，小红！
```

**题目2：** `41`（3×10 + 2×5 + 1 = 41）

**题目3：** `和是15`

**题目4：** `小明喜欢：('游泳', '画画', '读书')`

**题目5：**
```
5 10 20
5 10 30
```

**题目6：**
```
['苹果']
['香蕉']
```
（因为 items=None 每次创建新列表，不会互相干扰）

### 练习三：找错改错

**题目1：** 位置参数在关键字参数后面
```python
# 改正：
func(1, 2, c=3)  # 或 func(1, 2, 3)
```

**题目2：** 默认参数放在位置参数前面
```python
# 改正：
def func(b, a=10):  # 把默认参数放到后面
    print(a, b)
```

**题目3：** 关键字参数在位置参数前面
```python
# 改正：
make_drink("咖啡", sugar=False)  # 位置参数在前
```

**题目4：** 空参数时报 ZeroDivisionError
```python
# 改正：
def average(*args):
    if not args:
        return 0
    return sum(args) / len(args)
```

### 练习四：补全代码

**补全代码①：**
```python
def create_invite(name, title="同学", greeting="你好"):
    print(f"{greeting}，{name}{title}！")
    print("欢迎参加本次Python编程活动！")
```

**补全代码②：**
```python
def describe_photos(*photos):
    count = len(photos)
    print(f"本次共有 {count} 张照片：")
    for i, photo in enumerate(photos, 1):
        print(f"  第{i}张：{photo}")
```

**补全代码③：**
```python
def make_pizza(size, *toppings):
    print(f"制作 {size}寸披萨，配料：")
    for topping in toppings:
        print(f"  - {topping}")
```

### 练习五：开放挑战

```python
def calculator(operation, *args):
    if not args:
        return 0
    if operation == "add":
        return sum(args)
    elif operation == "mul":
        result = 1
        for n in args:
            result *= n
        return result
    elif operation == "max":
        return max(args)
    elif operation == "min":
        return min(args)
    else:
        return None

# 运行结果
calculator("add", 1, 2, 3, 4)    → 10
calculator("mul", 2, 3, 4)       → 24
calculator("max", 10, 5, 8, 20)  → 20
calculator("min", 10, 5, 8, 20)  → 5
calculator("add")                → 0
```

---

## 五、课后练习卡答案

### 选择题
1. **B**（关键字参数）
2. **C**（默认参数可以不传值，使用定义时的默认值）
3. **C**（a=1 位置参数，b 用默认值 5，c 用关键字传入 20 → 1 5 20）
4. **D**（名字可以不叫 args，但约定俗成叫 args）

### 填空题
1. **关键字**参数
2. **默认**参数
3. `*toppings`
4. **位置**参数
5. 
```
重复：加油
重复：努力
重复：坚持
```
6. **位置**参数必须在**关键字**参数前面

### 写出输出
1. `三明治配料：('火腿', '生菜', '番茄', '芝士')`
2. `欢迎 小红` 然后 `Hello 小刚`
3. `6`（1+2+3=6）
4. `小明 {'age': 10, 'city': '北京', 'hobby': '编程'}`

### 简答题参考要点

**关键字参数的好处：**
1. **不用记住参数顺序**：调用时用 `name=value` 方式传参，参数顺序可以任意排列，降低记忆负担
2. **代码可读性高**：一看就知道每个值传给哪个参数，代码自解释
3. **可配合默认参数跳过中间参数**：只传想改的参数，其他用默认值

### 附加题答案

```python
def order_dish(dish_name, *add_ons, quantity=1):
    if add_ons:
        add_on_str = "、".join(add_ons)
        print(f"【订单】{quantity} 份 {dish_name}，加料：{add_on_str}")
    else:
        print(f"【订单】{quantity} 份 {dish_name}")

# 运行结果
order_dish("牛肉面", "卤蛋", "豆皮")
→ 【订单】1 份 牛肉面，加料：卤蛋、豆皮

order_dish("奶茶", "珍珠", "椰果", "布丁", quantity=2)
→ 【订单】2 份 奶茶，加料：珍珠、椰果、布丁

order_dish("蛋炒饭")
→ 【订单】1 份 蛋炒饭
```

---

## 六、常见学生错误与纠正

| 错误表现 | 原因 | 纠正方法 |
|---------|------|---------|
| 写成 `func(1, c=3, 2)` | 位置参数跟在关键字参数后面 | 口诀："位置参数排前面，关键字在后不乱窜" |
| 定义时 `def func(a=10, b)` | 默认参数放在位置参数前面 | 默认参数必须放在位置参数之后 |
| 认为 *args 名字必须叫 args | 混淆语法要求和命名约定 | `*` 是语法，args 只是约定俗成 |
| 默认参数用 `[]` 导致累积 | 不理解默认参数只初始化一次 | 用 None 做默认值，函数内创建新列表 |
| 认为位置参数不可读 | 没体验过关键字参数的好处 | 对比两种调用，让学生自己判断可读性 |
| `*args` 和 `**kwargs` 混淆 | 跳过知识边界 | 本节课只讲 *args，**kwargs 后续课程涉及 |

---

## 七、扩展建议

### 课后追问
- "如果我想定义一个函数，既能接收任意数量的位置参数，又能接收任意数量的关键字参数，怎么写？" → `def func(*args, **kwargs)`
- "默认参数的值可以是表达式的结果吗？" → 可以，但只在定义时计算一次
- "*args 接收的是列表还是元组？为什么？" → 元组，因为元组不可变，数据更安全

### 游戏化建议
1. **参数接力赛**：教师喊出参数类型（位置/关键字/默认），学生快速在黑板上写出对应的调用代码
2. **找茬游戏**：故意写出有语法错误的参数混用代码，让学生快速纠错
3. **点餐模拟**：三个学生一组，一个当厨师（写函数定义），一个当前台（写函数调用），一个当顾客（提需求），用默认参数和 *args 模拟真实点餐场景
