Files
2026-07-28 16:19:52 +08:00

490 lines
11 KiB
Markdown
Raw Permalink 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-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`
- [ ] 能回答七道思考题。