# 第 1-8 课:列表 ## 一、本课目标 完成本课后,你应该能够: 1. 解释列表为什么可以保存多个数据; 2. 创建列表和空列表; 3. 使用索引、负索引和切片读取列表; 4. 修改列表中的指定元素; 5. 添加和删除列表元素; 6. 查找并统计列表中的元素; 7. 对列表进行排序和反转; 8. 使用循环遍历列表; 9. 在确实需要位置时使用索引遍历; 10. 理解列表可变性; 11. 区分直接赋值与列表复制; 12. 看懂简单的二维列表。 ## 二、前置知识 开始本课前,你应该已经掌握: - 变量和基础数据类型; - 字符串的索引与切片; - `if` 条件判断; - `for` 循环; - `in` 成员判断; - 字符串的 `split()` 和 `join()`。 ## 三、为什么需要列表 如果要保存多个 Agent 开发工具,可以分别创建变量: ```python tool_1 = "Python" tool_2 = "FastAPI" tool_3 = "Django" ``` 数据增加后,这种方式难以统一遍历、排序和管理。 列表(List)可以使用一个变量保存多个有顺序的数据: ```python agent_tools = ["Python", "FastAPI", "Django"] ``` 列表使用英文方括号 `[]`,元素之间使用英文逗号分隔。 ## 四、创建列表 ### 4.1 创建包含数据的列表 ```python agent_tools = ["Python", "FastAPI", "Django"] ``` ### 4.2 创建空列表 ```python agent_tools = [] ``` 空列表暂时没有元素,但后续可以添加数据。 ### 4.3 列表可以保存不同类型 ```python learning_record = ["Python", 8, 2.5, True] ``` Python 允许一个列表保存不同类型的数据。不过实际开发中,同一个列表通常保存含义相近的数据,这样更容易理解和处理。 ## 五、列表是有顺序的 列表中的每个元素都有位置,索引从 `0` 开始: ```text 元素: Python FastAPI Django 正索引: 0 1 2 负索引: -3 -2 -1 ``` 读取元素: ```python agent_tools = ["Python", "FastAPI", "Django"] print(agent_tools[0]) print(agent_tools[-1]) ``` 输出: ```text Python Django ``` 如果访问不存在的索引,会产生 `IndexError`。 ## 六、列表切片 列表切片与字符串切片规则相同:包含开始索引,不包含结束索引。 ```python agent_tools = ["Python", "FastAPI", "Django", "LangChain"] print(agent_tools[0:2]) print(agent_tools[:3]) print(agent_tools[2:]) print(agent_tools[::-1]) ``` 切片返回一个新列表,不会直接修改原列表。 ## 七、列表长度 使用 `len()` 获取元素数量: ```python agent_tools = ["Python", "FastAPI", "Django"] tool_count = len(agent_tools) print(tool_count) ``` 输出为 `3`。 访问首尾元素前,可以先判断列表是否非空: ```python if agent_tools: print(agent_tools[0]) print(agent_tools[-1]) else: print("工具列表为空") ``` 空列表在条件中会被当作 `False`。 ## 八、列表是可变的 字符串不可变,但列表是可变的(Mutable),可以直接修改某个位置的元素: ```python agent_tools = ["Python", "Flask", "Django"] agent_tools[1] = "FastAPI" print(agent_tools) ``` 输出: ```text ['Python', 'FastAPI', 'Django'] ``` 必须确保索引存在,不能通过一个超出范围的索引直接添加元素。 ## 九、添加元素 ### 9.1 `append()` 追加到末尾 ```python agent_tools = ["Python", "FastAPI"] agent_tools.append("Django") ``` `append()` 每次把一个元素添加到列表末尾。 ### 9.2 `insert()` 插入指定位置 ```python agent_tools.insert(1, "Pydantic") ``` 第一个参数是插入索引,第二个参数是新元素。原来位于该位置及后面的元素会向后移动。 ### 9.3 `extend()` 添加多个元素 ```python agent_tools.extend(["LangChain", "OpenAI SDK"]) ``` `extend()` 会依次加入另一个列表中的元素。 请比较: ```python agent_tools.append(["LangChain", "OpenAI SDK"]) ``` `append()` 会把整个列表当作一个元素加入,形成嵌套列表;`extend()` 才是逐个加入多个元素。 ## 十、删除元素 ### 10.1 `remove()` 按内容删除 ```python agent_tools.remove("Django") ``` `remove()` 删除第一个匹配的元素。如果元素不存在,会产生 `ValueError`。 安全写法: ```python if "Django" in agent_tools: agent_tools.remove("Django") ``` ### 10.2 `pop()` 按位置删除并返回元素 ```python removed_tool = agent_tools.pop() ``` 不传索引时删除最后一个元素,并把被删除的数据返回。 ```python removed_tool = agent_tools.pop(1) ``` 传入索引时删除指定位置。 ### 10.3 `del` 删除指定位置 ```python del agent_tools[0] ``` `del` 是 Python 关键字,不会返回被删除的数据。 ### 10.4 `clear()` 清空列表 ```python agent_tools.clear() ``` 执行后列表仍然存在,但元素数量变为 `0`。 ## 十一、查找和统计 ### 11.1 使用 `in` ```python contains_fastapi = "FastAPI" in agent_tools ``` ### 11.2 `index()` 查找位置 ```python if "FastAPI" in agent_tools: fastapi_index = agent_tools.index("FastAPI") ``` 找不到时,`index()` 会产生 `ValueError`,因此可以先使用 `in`。 ### 11.3 `count()` 统计次数 ```python python_count = agent_tools.count("Python") ``` 找不到时返回 `0`,不会报错。 ## 十二、排序和反转 ### 12.1 `sort()` 修改原列表 ```python scores = [80, 95, 70, 88] scores.sort() print(scores) ``` 默认从小到大排序。 降序排列: ```python scores.sort(reverse=True) ``` 英文字符串通常按照字符编码顺序排序,大小写可能影响结果。 ### 12.2 `reverse()` 反转当前顺序 ```python agent_tools.reverse() ``` `reverse()` 只把当前顺序倒过来,并不按大小重新排序。 ### 12.3 `sorted()` 返回新列表 ```python original_scores = [80, 95, 70] sorted_scores = sorted(original_scores) ``` `sorted()` 返回排序后的新列表,原列表保持不变。 ## 十三、遍历列表 ### 13.1 直接遍历元素 ```python for tool in agent_tools: print(tool) ``` 只需要元素时,优先直接遍历,代码最清晰。 ### 13.2 需要索引时使用 `range(len(...))` ```python for index in range(len(agent_tools)): print(f"{index + 1}. {agent_tools[index]}") ``` 只有确实需要修改指定位置或使用索引时,才采用这种方式。 ### 13.3 使用 `enumerate()` 同时取得编号和元素 ```python for number, tool in enumerate(agent_tools, start=1): print(f"{number}. {tool}") ``` `enumerate()` 会同时提供编号和元素,通常比 `range(len(...))` 更易读。 本课先学会模仿这种常用写法,函数返回多个数据的原理会在后续课程继续讲解。 ## 十四、简单二维列表 列表中的元素也可以是列表: ```python tool_records = [ ["Python", "基础编程"], ["FastAPI", "接口开发"], ["Django", "Web 应用"], ] ``` 读取 FastAPI 的用途: ```python print(tool_records[1][1]) ``` 第一个索引选择第二条记录,第二个索引选择该记录中的第二个元素。 二维列表适合简单表格数据,但真实业务数据常使用字典、对象或数据库表达,将在后续课程学习。 ## 十五、直接赋值与复制 ### 15.1 直接赋值不会创建独立列表 ```python original_tools = ["Python", "FastAPI"] backup_tools = original_tools backup_tools.append("Django") print(original_tools) print(backup_tools) ``` 两个变量都会看到 `Django`,因为它们指向同一个列表对象。 ### 15.2 使用 `copy()` 创建浅复制 ```python original_tools = ["Python", "FastAPI"] backup_tools = original_tools.copy() backup_tools.append("Django") ``` 对于本课这种只包含字符串的简单列表,修改副本不会影响原列表。 `copy()` 创建的是浅复制(Shallow Copy)。嵌套列表中的共享问题属于进阶内容,本课暂不展开。 ## 十六、方法返回值的常见误区 下面写法是错误思路: ```python agent_tools = ["Python", "FastAPI"] result = agent_tools.append("Django") print(result) ``` 输出为 `None`。`append()`、`sort()`、`reverse()` 等方法直接修改原列表,通常不返回修改后的列表。 正确观察方式: ```python agent_tools.append("Django") print(agent_tools) ``` ## 十七、运行本课示例 在 PowerShell 中执行: ```powershell cd D:\Code\Python\01_python基础\1_8_列表 python lists.py ``` 示例无需用户输入,会依次展示创建、读取、修改、增删、查询、排序、遍历、二维列表和复制行为。 ## 十八、常见错误 ### 18.1 索引越界 访问不存在的位置会产生 `IndexError`。访问首尾元素前应确认列表非空。 ### 18.2 删除不存在的元素 `remove()` 删除不存在的值会产生 `ValueError`,可以先使用 `in` 判断。 ### 18.3 混淆 `append()` 与 `extend()` - `append()` 添加一个元素; - `extend()` 依次添加多个元素。 ### 18.4 把排序结果赋值回列表 ```python agent_tools = agent_tools.sort() ``` 这会让 `agent_tools` 变成 `None`。应先调用,再读取原列表。 ### 18.5 直接赋值误以为完成复制 `backup = original` 只是增加另一个变量名,并未创建独立列表。 ## 十九、课堂练习 打开 `practice.py`,完成“Agent 工具清单管理器”。 运行命令: ```powershell python practice.py ``` 练习会要求你完成列表的创建、修改、添加、删除、查询、排序、遍历和复制。 ## 二十、思考题 1. 列表和字符串在可变性方面有什么区别? 2. `append()` 与 `extend()` 有什么区别? 3. `remove()` 与 `pop()` 有什么区别? 4. `sort()` 与 `sorted()` 对原列表的影响有什么不同? 5. 为什么访问列表首项前要检查列表是否为空? 6. 为什么 `backup = original` 不能得到独立副本? 7. 只需要元素时,为什么优先直接遍历列表? ## 二十一、本课小结 - 列表可以保存多个有顺序的数据; - 列表索引从 `0` 开始,也支持负索引和切片; - 列表是可变对象,可以直接修改元素; - `append()`、`insert()`、`extend()` 用于添加; - `remove()`、`pop()`、`del`、`clear()` 用于删除; - `index()` 和 `count()` 用于查找统计; - `sort()` 修改原列表,`sorted()` 返回新列表; - `for` 和 `enumerate()` 可以遍历列表; - 直接赋值不会创建独立副本,简单列表可使用 `copy()`。 ## 二十二、验收标准 - [ ] 能创建列表和空列表; - [ ] 能使用索引和切片读取列表; - [ ] 能修改、添加和删除元素; - [ ] 能安全查找指定元素; - [ ] 能排序并遍历列表; - [ ] 能解释列表可变性; - [ ] 能区分直接赋值与 `copy()`; - [ ] 能完成并运行 `practice.py`; - [ ] 能回答七道思考题。