feat(python基础): 新增元组教学课程

This commit is contained in:
zhiye.sun
2026-07-29 14:59:37 +08:00
parent 30be6923ed
commit 4181826067
4 changed files with 688 additions and 5 deletions

View File

@@ -0,0 +1,456 @@
# 第 1-9 课:元组
## 一、本课目标
完成本课后,你应该能够:
1. 解释元组与列表的主要区别;
2. 创建空元组、单元素元组和多元素元组;
3. 使用索引、负索引和切片读取元组;
4. 使用 `len()``in``index()``count()`
5. 使用 `for` 遍历元组;
6. 理解元组不可变的含义;
7. 使用元组打包和解包多个数据;
8. 使用星号收集解包后的剩余元素;
9. 完成两个变量的交换;
10. 在列表和元组之间进行转换;
11. 判断什么场景更适合使用元组。
## 二、前置知识
开始本课前,你应该已经掌握:
- 列表的创建、索引和切片;
- 列表的可变性;
- 使用 `for` 遍历多个数据;
- 使用 `in``index()``count()`
- 条件判断与 f-string。
## 三、元组是什么
元组Tuple是一个有顺序的数据集合。
```python
agent_config = ("gpt-5", 0.7, 2000)
```
元组与列表很相似:
- 都能保存多个数据;
- 都有顺序;
- 都支持索引、负索引和切片;
- 都能使用 `len()``for`
最重要的区别是:
- 列表是可变的,可以添加、删除和修改元素;
- 元组是不可变的,创建后不能替换、增加或删除元素。
元组适合表达“创建后不希望被随意改变的一组数据”。
## 四、创建元组
### 4.1 多元素元组
```python
agent_config = ("gpt-5", 0.7, 2000)
```
通常使用英文圆括号 `()` 包围元素,元素之间使用英文逗号分隔。
### 4.2 空元组
```python
empty_tuple = ()
```
使用 `len(empty_tuple)` 会得到 `0`
### 4.3 单元素元组
单元素元组必须在元素后保留英文逗号:
```python
single_tool = ("Python",)
```
如果没有逗号:
```python
not_a_tuple = ("Python")
```
Python 会把圆括号理解为普通分组,变量实际保存的是字符串。
可以使用 `type()` 验证:
```python
print(type(("Python",))) # tuple
print(type(("Python"))) # str
```
创建元组时,真正决定元组的是逗号,而不只是圆括号。
### 4.4 省略圆括号
```python
agent_position = "北京", "朝阳区"
```
只要存在用于分隔元素的逗号Python 也会创建元组。为了新手阅读清晰,本课大多数场景仍保留圆括号。
## 五、元组可以保存不同类型
```python
agent_config = ("gpt-5", 0.7, 2000, True)
```
这个元组依次保存:
- 字符串:模型名称;
- 浮点数:温度参数;
- 整数:最大输出长度;
- 布尔值:是否启用。
虽然允许混合类型,但每个位置应具有明确、稳定的含义。
## 六、索引和负索引
元组索引从 `0` 开始:
```text
元素: gpt-5 0.7 2000
正索引: 0 1 2
负索引: -3 -2 -1
```
```python
agent_config = ("gpt-5", 0.7, 2000)
print(agent_config[0])
print(agent_config[-1])
```
访问不存在的索引会产生 `IndexError`
访问首尾元素前,可以先判断元组是否非空:
```python
if agent_config:
print(agent_config[0])
print(agent_config[-1])
```
## 七、元组切片
切片规则与字符串、列表相同:包含开始索引,不包含结束索引。
```python
agent_config = ("gpt-5", 0.7, 2000, True)
basic_config = agent_config[:2]
remaining_config = agent_config[2:]
reversed_config = agent_config[::-1]
```
元组切片返回一个新元组,不会修改原元组。
## 八、长度、成员判断和统计
### 8.1 `len()`
```python
config_count = len(agent_config)
```
### 8.2 `in`
```python
contains_model = "gpt-5" in agent_config
```
### 8.3 `index()`
```python
if "gpt-5" in agent_config:
model_index = agent_config.index("gpt-5")
```
元素不存在时,`index()` 会产生 `ValueError`,因此可以先使用 `in` 判断。
### 8.4 `count()`
```python
status_history = ("成功", "失败", "成功")
success_count = status_history.count("成功")
```
## 九、遍历元组
```python
supported_models = ("gpt-5", "o3", "gpt-4.1")
for model in supported_models:
print(model)
```
需要编号时可以使用 `enumerate()`
```python
for number, model in enumerate(supported_models, start=1):
print(f"{number}. {model}")
```
## 十、元组不可变
下面的操作都不允许:
```text
agent_config[0] = "o3"
agent_config.append("新数据")
del agent_config[0]
```
元组没有 `append()``remove()``pop()` 等修改方法。
不可变带来的好处包括:
- 表达数据结构是固定的;
- 减少意外修改;
- 阅读代码时更容易判断数据不会被增删;
- 某些场景中元组可以作为字典的键,后续学习字典时会再讲。
## 十一、需要“修改”元组怎么办
不能直接修改原元组,但可以创建新元组:
```python
old_config = ("gpt-5", 0.7, 2000)
new_config = ("o3",) + old_config[1:]
print(old_config)
print(new_config)
```
原元组保持不变,`new_config` 是全新的元组。
也可以先转换为列表,修改后再转回元组:
```python
config_list = list(old_config)
config_list[0] = "o3"
new_config = tuple(config_list)
```
如果数据经常需要修改,直接使用列表通常更合适,不应反复转换。
## 十二、元组拼接和重复
虽然不能修改原元组,但可以通过运算创建新元组。
### 12.1 拼接
```python
basic_config = ("gpt-5", 0.7)
limit_config = (2000, True)
full_config = basic_config + limit_config
```
### 12.2 重复
```python
default_status = ("待处理",) * 3
```
结果为:
```text
('待处理', '待处理', '待处理')
```
这两种操作都返回新元组。
## 十三、元组打包
把多个数据放进一个元组称为打包Packing
```python
agent_snapshot = "gpt-5", 0.7, 2000
```
三个数据被打包成一个元组。
使用圆括号可以让含义更清楚:
```python
agent_snapshot = ("gpt-5", 0.7, 2000)
```
## 十四、元组解包
把元组中的元素分别赋给多个变量称为解包Unpacking
```python
agent_snapshot = ("gpt-5", 0.7, 2000)
model_name, temperature, max_tokens = agent_snapshot
```
解包后:
- `model_name` 保存 `"gpt-5"`
- `temperature` 保存 `0.7`
- `max_tokens` 保存 `2000`
左侧变量数量必须与右侧元素数量一致,否则会产生 `ValueError`
## 十五、使用星号收集剩余元素
```python
agent_snapshot = ("gpt-5", 0.7, 2000, True)
model_name, *other_settings = agent_snapshot
```
解包后:
- `model_name` 是字符串 `"gpt-5"`
- `other_settings` 是列表 `[0.7, 2000, True]`
星号变量会把剩余元素收集到列表中。
一个解包表达式中只能有一个星号变量:
```python
first_value, *middle_values, last_value = agent_snapshot
```
## 十六、交换变量
传统思路通常需要临时变量。Python 可以使用打包和解包直接交换:
```python
primary_model = "gpt-5"
backup_model = "o3"
primary_model, backup_model = backup_model, primary_model
```
右侧先打包为元组,再解包给左侧变量。
## 十七、元组内部包含可变对象
请观察:
```python
agent_data = ("gpt-5", ["搜索", "计算"])
agent_data[1].append("写作")
```
元组本身仍然不可变:不能把 `agent_data[1]` 替换成另一个列表。
但是第二个元素指向的列表本身是可变对象,因此列表内部可以改变。
这说明元组不可变的准确含义是:元组保存的元素引用不能被替换,并不保证元素内部的数据一定不可变。
这是一个重要边界。本课能看懂即可,后续学习对象和引用时会继续加深理解。
## 十八、列表与元组如何选择
适合使用列表:
- 数据需要经常添加、删除、修改;
- 数量会变化;
- 表达任务清单、工具集合、学习记录。
适合使用元组:
- 数据结构固定;
- 创建后不希望改变;
- 表达坐标、颜色值、固定配置、数据库返回的一条固定结构记录;
- 需要通过解包一次取得多个数据。
不要因为元组“看起来更高级”而强行使用。应该根据数据是否需要变化来选择。
## 十九、运行本课示例
在 PowerShell 中执行:
```powershell
cd D:\Code\Python\01_python基础\1_9_元组
python tuples.py
```
示例无需用户输入,会依次展示创建、读取、切片、统计、遍历、拼接、转换、打包、解包和变量交换。
## 二十、常见错误
### 20.1 单元素元组忘记逗号
```python
single_value = ("Python",)
```
最后的逗号不可省略。
### 20.2 尝试直接修改元组
元组不支持按索引赋值,也没有列表的增删方法。
### 20.3 解包变量数量不匹配
三个元素通常需要三个接收变量,除非使用星号收集剩余元素。
### 20.4 认为圆括号一定代表元组
`("Python")` 是字符串;逗号才是创建单元素元组的关键。
### 20.5 把元组中的列表也当作完全不可变
元组不能替换元素,但元组内部的列表仍然可以修改自身内容。
## 二十一、课堂练习
打开 `practice.py`完成“Agent 固定配置快照”。
运行命令:
```powershell
python practice.py
```
练习会要求你创建配置元组、读取和切片、查找统计、解包、转换以及比较原配置和新配置。
## 二十二、思考题
1. 列表和元组最重要的区别是什么?
2. 为什么单元素元组必须保留逗号?
3. 元组切片会返回列表还是元组?
4. 解包时变量数量不匹配会发生什么?
5. 星号变量收集剩余元素后得到什么类型?
6. 为什么经常变化的数据更适合使用列表?
7. 元组中包含列表时,为什么列表内容仍然能够变化?
## 二十三、本课小结
- 元组是有顺序、不可变的数据集合;
- 单元素元组必须包含逗号;
- 元组支持索引、切片、遍历、成员判断和统计;
- 元组不能直接增删或替换元素;
- 需要新数据时,可以创建新元组或进行列表转换;
- 打包把多个数据组合成元组;
- 解包把元组元素分别赋给变量;
- 星号可以收集剩余元素;
- Python 可以通过打包解包交换变量;
- 固定结构适合元组,经常变化的数据适合列表。
## 二十四、验收标准
- [ ] 能创建空元组、单元素元组和多元素元组;
- [ ] 能使用索引和切片读取元组;
- [ ] 能使用 `len()``in``index()``count()`
- [ ] 能遍历元组;
- [ ] 能解释元组不可变;
- [ ] 能完成打包和解包;
- [ ] 能使用星号收集剩余元素;
- [ ] 能在列表和元组之间转换;
- [ ] 能完成并运行 `practice.py`
- [ ] 能回答七道思考题。

View File

@@ -0,0 +1,120 @@
# 第 1-9 课课堂练习Agent 固定配置快照
#
# 完成要求:
# 1. 根据注释完成元组的创建、读取、统计、转换和解包。
# 2. 使用有意义的英文蛇形变量名。
# 3. 调用 index() 前先判断元素是否存在。
# 4. 不要尝试直接修改元组元素。
# 5. 不要删除题目注释。
# 6. 完成后运行本文件并核对预期结果。
# 练习一:创建元组 agent_config依次保存
# 模型名称 "gpt-5"、温度 0.7、最大长度 2000、启用状态 True。
# 练习二:创建以下两个元组:
# 1. 空元组 empty_config
# 2. 只包含 "Python" 的单元素元组 single_tool。
# 使用 type() 输出 single_tool 的类型,确认它是 tuple。
# 练习三:输出 agent_config 的以下信息:
# 1. 完整元组;
# 2. 元素数量;
# 3. 第一个元素;
# 4. 最后一个元素。
# 读取首尾元素前先判断 agent_config 是否非空。
# 练习四:完成以下切片:
# 1. 取得前两个元素并保存到 basic_config
# 2. 取得后两个元素并保存到 limit_config
# 3. 反转元组并保存到 reversed_config。
# 练习五:完成成员判断和查找:
# 1. 判断 agent_config 是否包含 "gpt-5",保存到 contains_model
# 2. 如果包含,使用 index() 保存位置到 model_index
# 3. 如果不包含,让 model_index 保存 -1。
# 练习六:创建状态元组 status_history
# "成功"、"失败"、"成功"、"成功"、"失败"。
# 使用 count() 统计 "成功",保存到 success_count。
# 练习七:使用 enumerate(agent_config, start=1) 遍历配置。
# 按照“1. gpt-5”这样的格式输出编号和配置值。
# 练习八:解包 agent_config。
# 分别使用 model_name、temperature、max_tokens、is_enabled 接收四个元素。
# 练习九:使用星号解包。
# 把 agent_config 的第一个元素保存到 first_setting
# 把其余元素收集到 other_settings
# 输出 other_settings 及其数据类型。
# 练习十:通过元组拼接创建新配置 new_config。
# 新配置的第一个元素应为 "o3",其余元素沿用 agent_config 的后三个元素。
# 不允许直接修改 agent_config。
# 练习十一:将 agent_config 转换成列表 config_list。
# 把列表中的温度修改为 0.3,再转换回元组 converted_config。
# 分别输出 agent_config 和 converted_config确认原配置没有改变。
# 练习十二:交换两个变量:
# primary_model 初始为 "gpt-5"
# backup_model 初始为 "o3"
# 不使用第三个临时变量,完成交换并输出结果。
# 练习十三:创建元组 agent_capabilities
# 第一个元素为 "gpt-5"
# 第二个元素为列表 ["搜索", "计算"]。
# 向内部列表追加 "写作",再输出整个元组。
# 思考:为什么元组不可变,但这个操作仍然允许?
# 练习十四:使用 30 个等号输出分隔线,再输出最终配置报告:
# 1. agent_config
# 2. basic_config
# 3. limit_config
# 4. reversed_config
# 5. contains_model
# 6. model_index
# 7. success_count
# 8. 解包后的四个变量;
# 9. new_config
# 10. converted_config
# 11. 交换后的 primary_model 和 backup_model
# 12. agent_capabilities。
# 预期核心结果:
# single_tool 的类型为 tuple
# contains_model = True
# model_index = 0
# success_count = 3
# other_settings 是列表;
# new_config 的模型为 o3
# converted_config 的温度为 0.3
# 原 agent_config 保持不变;
# 交换后 primary_model 为 o3backup_model 为 gpt-5
# agent_capabilities 内部列表包含“写作”。
# 完成后进行自查:
# 1. 单元素元组是否保留了逗号;
# 2. 读取首尾元素前是否判断元组非空;
# 3. index() 前是否使用 in 判断;
# 4. 解包变量数量是否与元素数量一致;
# 5. 星号变量是否得到列表;
# 6. 是否没有直接修改 agent_config
# 7. 转换后的配置是否没有影响原配置;
# 8. 变量交换是否没有使用第三个临时变量。

View File

@@ -0,0 +1,107 @@
# 第 1-9 课示例:元组
#
# 本文件使用 Agent 固定配置作为统一示例,演示元组的主要操作。
# 示例无需用户输入,可以直接运行并对照注释观察结果。
# 一、创建多元素元组、空元组和单元素元组
agent_config = ("gpt-5", 0.7, 2000, True)
empty_config = ()
single_model = ("gpt-5",)
print(f"完整配置:{agent_config}")
print(f"空元组长度:{len(empty_config)}")
print(f"单元素元组:{single_model}")
print(f"单元素元组类型:{type(single_model)}")
# 二、索引和负索引
print(f"模型名称:{agent_config[0]}")
print(f"是否启用:{agent_config[-1]}")
# 三、切片
# 元组切片返回一个新元组。
basic_config = agent_config[:2]
remaining_config = agent_config[2:]
print(f"基础配置切片:{basic_config}")
print(f"其余配置切片:{remaining_config}")
# 四、成员判断、查找和统计
contains_model = "gpt-5" in agent_config
model_index = agent_config.index("gpt-5")
status_history = ("成功", "失败", "成功", "成功")
success_count = status_history.count("成功")
print(f"是否包含 gpt-5{contains_model}")
print(f"gpt-5 的索引:{model_index}")
print(f"成功出现次数:{success_count}")
# 五、遍历元组
supported_models = ("gpt-5", "o3", "gpt-4.1")
for number, model in enumerate(supported_models, start=1):
print(f"{number}. {model}")
# 六、拼接和重复
basic_settings = ("gpt-5", 0.7)
limit_settings = (2000, True)
full_settings = basic_settings + limit_settings
default_statuses = ("待处理",) * 3
print(f"拼接结果:{full_settings}")
print(f"重复结果:{default_statuses}")
# 七、通过创建新元组表达配置变更
# 原元组不会改变,新配置使用新的模型名称和原配置的其余元素。
new_config = ("o3",) + agent_config[1:]
print(f"原配置:{agent_config}")
print(f"新配置:{new_config}")
# 八、列表和元组转换
config_list = list(agent_config)
config_list[1] = 0.3
converted_config = tuple(config_list)
print(f"转换并修改后的配置:{converted_config}")
# 九、打包和解包
agent_snapshot = ("gpt-5", 0.7, 2000)
model_name, temperature, max_tokens = agent_snapshot
print(f"解包模型:{model_name}")
print(f"解包温度:{temperature}")
print(f"解包最大长度:{max_tokens}")
# 十、使用星号收集剩余元素
first_setting, *other_settings = agent_config
print(f"第一个配置:{first_setting}")
print(f"其余配置列表:{other_settings}")
print(f"其余配置的数据类型:{type(other_settings)}")
# 十一、交换两个变量
primary_model = "gpt-5"
backup_model = "o3"
primary_model, backup_model = backup_model, primary_model
print(f"交换后的主模型:{primary_model}")
print(f"交换后的备用模型:{backup_model}")
# 十二、元组内部包含列表
# 元组不能替换第二个元素,但第二个元素指向的列表可以修改自身内容。
agent_data = ("gpt-5", ["搜索", "计算"])
agent_data[1].append("写作")
print(f"包含列表的元组:{agent_data}")