Files
PythonLearn/01_python基础/1_13_函数进阶/README.md

382 lines
9.1 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 第 1-13 课:函数进阶
## 一、本课目标
完成本课后,你将能够:
1. 使用 `return` 一次返回多个结果;
2. 使用提前返回减少不必要的嵌套;
3. 使用 `*args` 接收任意数量的位置参数;
4. 使用 `**kwargs` 接收任意数量的关键字参数;
5. 使用 `*``**` 在调用函数时解包数据;
6. 根据不同任务选择普通参数、`*args``**kwargs`
7. 继续练习让函数保持清晰、职责单一。
## 二、前置知识
学习本课前,需要理解:
- 如何使用 `def` 定义函数;
- 如何调用函数;
- 位置参数、关键字参数和默认参数;
- `print()``return` 的区别;
- 列表、元组和字典;
- 条件判断和循环。
## 三、一次返回多个结果
一个函数可以在 `return` 后面写多个值:
```python
def get_agent_summary(agent):
return agent["name"], len(agent.get("tools", []))
agent_name, tool_count = get_agent_summary({
"name": "代码助手",
"tools": ["搜索", "终端"],
})
print(agent_name)
print(tool_count)
```
Python 实际上会先把多个返回值组合成一个元组,再把元组解包给多个变量。
也可以只用一个变量接收:
```python
summary = get_agent_summary({"name": "聊天助手", "tools": []})
print(summary)
print(type(summary))
```
此时 `summary` 是元组,例如 `("聊天助手", 0)`
## 四、提前返回
`return` 不只负责返回结果,还会立即结束当前函数。
```python
def get_agent_status(agent):
if not agent.get("enabled", False):
return "停用"
return "启用"
```
如果 Agent 没有启用,函数执行第一个 `return` 后就结束,不会继续执行下面的代码。
这种写法称为提前返回Early Return。它适合先处理无效数据或特殊情况避免出现太多层缩进。
## 五、使用 `*args` 接收多个位置参数
有时无法提前确定调用者会传入几个位置参数,这时可以使用 `*args`
```python
def count_tools(*tools):
return len(tools)
print(count_tools("搜索"))
print(count_tools("搜索", "终端", "计算器"))
```
这里的 `args` 是 arguments 的缩写,表示“多个参数”。
需要注意:
- 参数名前面的 `*` 才是关键;
- `args` 是约定俗成的名称,也可以换成其他名称;
- 函数内部的 `tools` 是一个元组;
- 即使没有传入任何工具,`tools` 也是空元组。
```python
def show_tools(*tools):
print(tools)
print(type(tools))
```
## 六、普通参数和 `*args` 一起使用
普通参数可以写在 `*args` 前面:
```python
def build_tool_message(agent_name, *tools):
return f"{agent_name} 拥有 {len(tools)} 个工具"
message = build_tool_message("代码助手", "搜索", "终端")
print(message)
```
调用时,第一个位置参数交给 `agent_name`,剩余位置参数都被收集到 `tools` 元组中。
## 七、使用 `**kwargs` 接收多个关键字参数
如果无法提前确定调用者会传入哪些关键字参数,可以使用 `**kwargs`
```python
def build_agent_config(**config):
return config
agent_config = build_agent_config(
name="代码助手",
model="gpt-5",
enabled=True,
)
print(agent_config)
```
`kwargs` 是 keyword arguments 的缩写,中文可理解为“多个关键字参数”。
函数内部的 `config` 是字典:
```python
{
"name": "代码助手",
"model": "gpt-5",
"enabled": True,
}
```
同样,参数名前面的两个星号 `**` 才是关键,`kwargs` 只是常见命名。
## 八、普通参数和 `**kwargs` 一起使用
```python
def create_agent(name, **settings):
return {
"name": name,
"settings": settings,
}
agent = create_agent("代码助手", model="gpt-5", enabled=True)
print(agent)
```
`name` 接收普通参数,其他关键字参数被收集到 `settings` 字典中。
## 九、调用函数时使用 `*` 解包列表或元组
星号也可以出现在函数调用中。此时它表示把列表或元组中的元素依次作为位置参数传入。
```python
def add_three_numbers(first, second, third):
return first + second + third
numbers = [10, 20, 30]
total = add_three_numbers(*numbers)
print(total)
```
上面的调用相当于:
```python
total = add_three_numbers(10, 20, 30)
```
元素数量必须与函数所需的位置参数数量匹配,否则会产生 `TypeError`
## 十、调用函数时使用 `**` 解包字典
两个星号可以把字典解包成关键字参数:
```python
def describe_agent(name, model):
return f"{name} 使用 {model}"
agent_data = {
"name": "代码助手",
"model": "gpt-5",
}
description = describe_agent(**agent_data)
print(description)
```
上面的调用相当于:
```python
description = describe_agent(name="代码助手", model="gpt-5")
```
字典的键必须与函数参数名一致。
## 十一、如何选择参数形式
### 使用普通参数
参数数量固定、含义明确时,优先使用普通参数:
```python
def get_total(first_number, second_number):
return first_number + second_number
```
### 使用 `*args`
需要接收数量不固定的同类位置参数时使用:
```python
def count_tools(*tools):
return len(tools)
```
### 使用 `**kwargs`
需要接收数量或名称不固定的配置项时使用:
```python
def build_config(**config):
return config
```
不要为了显得代码高级而强行使用 `*args``**kwargs`。参数固定时,普通参数通常更清楚。
## 十二、完整示例
本课示例文件为:
```text
01_python基础/1_13_函数进阶/advanced_functions.py
```
示例会依次演示:
1. 返回多个结果;
2. 提前返回;
3. 使用 `*args`
4. 使用 `**kwargs`
5. 解包列表和字典后调用函数。
## 十三、运行方法
在项目根目录执行:
```powershell
python .\01_python基础\1_13_函数进阶\advanced_functions.py
```
运行练习:
```powershell
python .\01_python基础\1_13_函数进阶\practice.py
```
## 十四、示例运行结果
```text
一、返回多个结果
Agent 名称:代码助手
工具数量2
==============================
二、提前返回
启用
停用
==============================
三、任意数量的位置参数
工具数量3
==============================
四、任意数量的关键字参数
{'name': '代码助手', 'model': 'gpt-5', 'enabled': True}
==============================
五、调用时解包数据
数字总和60
代码助手 使用 gpt-5
```
字典的显示格式可能因环境而略有差异,但键和值应当一致。
## 十五、关键代码解析
```python
def count_tools(*tools):
return len(tools)
```
执行顺序如下:
1. 调用者传入零个或多个位置参数;
2. `*` 把这些参数收集到 `tools`
3. `tools` 在函数内部是元组;
4. `len()` 统计元组中的元素数量;
5. `return` 把数量交给调用者。
```python
def build_agent_config(**config):
return config
```
执行顺序如下:
1. 调用者传入零个或多个关键字参数;
2. `**` 把参数名称和值收集到 `config`
3. `config` 在函数内部是字典;
4. 函数把字典返回给调用者。
## 十六、常见错误
### 16.1 混淆 `*args` 和 `**kwargs`
- `*args` 收集位置参数,函数内部得到元组;
- `**kwargs` 收集关键字参数,函数内部得到字典。
### 16.2 忘记星号
`args``kwargs` 本身只是普通名称。真正产生收集效果的是 `*``**`
### 16.3 解包后的参数数量不匹配
如果函数需要三个参数,列表却只有两个元素,会产生 `TypeError`,表示调用时提供的参数数量不正确。
### 16.4 字典键与参数名不一致
使用 `**dictionary` 调用函数时,字典键必须能对应函数参数名。
### 16.5 在 `return` 后继续编写必须执行的代码
函数执行到 `return` 就会结束,写在同一执行路径后面的代码不会运行。
### 16.6 所有函数都使用可变参数
固定且明确的数据应继续使用普通参数。过度使用可变参数会降低可读性。
## 十七、课堂练习
打开:
```text
01_python基础/1_13_函数进阶/practice.py
```
练习题已经明确提供输入数据、实现步骤、返回要求和预期结果。请先独立完成,再进行验证。
## 十八、本课小结
1. `return value1, value2` 可以返回多个结果;
2. 多个返回值实际会组合成元组;
3. 提前返回可以尽早结束函数;
4. `*args` 收集位置参数并形成元组;
5. `**kwargs` 收集关键字参数并形成字典;
6. 调用函数时,`*` 可以解包列表或元组;
7. 调用函数时,`**` 可以解包字典;
8. 参数固定时应优先使用普通参数。
## 十九、验收标准
- 能正确接收函数的多个返回值;
- 能解释 `return` 为什么会结束函数;
- 能使用 `*args` 接收不同数量的位置参数;
- 能说明 `*args` 在函数内部是元组;
- 能使用 `**kwargs` 接收关键字参数;
- 能说明 `**kwargs` 在函数内部是字典;
- 能使用 `*` 解包列表或元组后调用函数;
- 能使用 `**` 解包字典后调用函数;
- 示例程序和练习程序可以正常运行。