From 4181826067e0f37475510dfaf62ab17b7e57682d Mon Sep 17 00:00:00 2001 From: "zhiye.sun" Date: Wed, 29 Jul 2026 14:59:37 +0800 Subject: [PATCH] =?UTF-8?q?feat(python=E5=9F=BA=E7=A1=80):=20=E6=96=B0?= =?UTF-8?q?=E5=A2=9E=E5=85=83=E7=BB=84=E6=95=99=E5=AD=A6=E8=AF=BE=E7=A8=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- 01_python基础/1_9_元组/README.md | 456 +++++++++++++++++++++++++++++ 01_python基础/1_9_元组/practice.py | 120 ++++++++ 01_python基础/1_9_元组/tuples.py | 107 +++++++ README.md | 10 +- 4 files changed, 688 insertions(+), 5 deletions(-) create mode 100644 01_python基础/1_9_元组/README.md create mode 100644 01_python基础/1_9_元组/practice.py create mode 100644 01_python基础/1_9_元组/tuples.py diff --git a/01_python基础/1_9_元组/README.md b/01_python基础/1_9_元组/README.md new file mode 100644 index 0000000..05b0ee8 --- /dev/null +++ b/01_python基础/1_9_元组/README.md @@ -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`; +- [ ] 能回答七道思考题。 diff --git a/01_python基础/1_9_元组/practice.py b/01_python基础/1_9_元组/practice.py new file mode 100644 index 0000000..f41b10e --- /dev/null +++ b/01_python基础/1_9_元组/practice.py @@ -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 为 o3,backup_model 为 gpt-5; +# agent_capabilities 内部列表包含“写作”。 + + +# 完成后进行自查: +# 1. 单元素元组是否保留了逗号; +# 2. 读取首尾元素前是否判断元组非空; +# 3. index() 前是否使用 in 判断; +# 4. 解包变量数量是否与元素数量一致; +# 5. 星号变量是否得到列表; +# 6. 是否没有直接修改 agent_config; +# 7. 转换后的配置是否没有影响原配置; +# 8. 变量交换是否没有使用第三个临时变量。 diff --git a/01_python基础/1_9_元组/tuples.py b/01_python基础/1_9_元组/tuples.py new file mode 100644 index 0000000..4e9868a --- /dev/null +++ b/01_python基础/1_9_元组/tuples.py @@ -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}") diff --git a/README.md b/README.md index 632ae53..bf08526 100644 --- a/README.md +++ b/README.md @@ -189,11 +189,11 @@ Python/ ## 当前学习进度 - 当前阶段:第一阶段——Python 基础语法。 -- 当前课程:`1_8_列表`。 -- 当前状态:第八课学习中。 -- 已完成课程:`1_1_hello_world` 至 `1_7_字符串`。 -- 已创建课程目录:`01_python基础/1_1_hello_world/` 至 `01_python基础/1_8_列表/`。 -- 下一步:阅读第八课讲义、运行列表示例并完成课堂练习。 +- 当前课程:`1_9_元组`。 +- 当前状态:第九课学习中。 +- 已完成课程:`1_1_hello_world` 至 `1_8_列表`。 +- 已创建课程目录:`01_python基础/1_1_hello_world/` 至 `01_python基础/1_9_元组/`。 +- 下一步:阅读第九课讲义、运行元组示例并完成课堂练习。 ## 建议环境