数据结构:列表、字典、元组与集合
Python 的容器类型,用于组织和存储多个数据。AI 中的训练数据、配置参数、模型结果,都用这些结构来管理。
list —— 列表(有序可变)
列表是 Python 最常用的数据结构。用方括号 [] 定义,可以存任意类型的数据,有顺序、可修改。
索引(Index)从 0 开始
列表中每个元素都有一个位置编号,从 0 开始(不是 1)。第一个元素是 list[0],第二个是 list[1]。Python 还支持负数索引,list[-1] 是最后一个元素,非常方便。
# 创建列表
losses = [2.5, 1.8, 1.2, 0.9, 0.7] # 每轮的损失值
labels = ["cat", "dog", "bird"] # 分类标签
mixed = [1, "hello", 3.14, True] # 可以存不同类型
# 索引访问
print(losses[0]) # 2.5(第一个)
print(losses[2]) # 1.2(第三个)
print(losses[-1]) # 0.7(最后一个)
print(losses[-2]) # 0.9(倒数第二个)
# 切片(slice):取一段数据
print(losses[1:3]) # [1.8, 1.2](索引1到2,不含3)
print(losses[:3]) # [2.5, 1.8, 1.2](前3个)
print(losses[2:]) # [1.2, 0.9, 0.7](从第3个到结束)
print(losses[::-1]) # [0.7, 0.9, 1.2, 1.8, 2.5](反转)
history = [2.5, 1.8] # 训练历史
# 添加元素
history.append(1.2) # 末尾添加:[2.5, 1.8, 1.2]
history.insert(0, 3.0) # 指定位置插入:[3.0, 2.5, 1.8, 1.2]
history.extend([0.9, 0.7]) # 合并另一个列表
# 删除元素
history.remove(3.0) # 删除第一个值为3.0的元素
last = history.pop() # 弹出并返回最后一个元素
# 查询
print(len(history)) # 元素数量
print(min(history)) # 最小值(最好的 loss)
print(max(history)) # 最大值
print(sum(history)) # 求和
print(sum(history)/len(history)) # 平均值
# 排序
history.sort() # 原地排序(升序)
history.sort(reverse=True) # 降序
sorted_h = sorted(history) # 返回新列表,不修改原列表
# 检查元素是否在列表中
print(0.9 in history) # True
AI 中的列表
在 AI 开发中,列表无处不在:train_losses = [] 记录训练损失曲线,messages = [{"role": "user", "content": "..."}] 构建对话历史,predictions = [] 收集模型预测结果。
列表推导式(List Comprehension)
这是 Python 的特色语法,可以用一行代码从现有列表创建新列表,比循环更简洁。在数据预处理中大量使用。
# 普通写法(循环)
squares = []
for x in range(5):
squares.append(x ** 2)
# 列表推导式(一行)= [表达式 for 变量 in 可迭代对象]
squares = [x ** 2 for x in range(5)]
print(squares) # [0, 1, 4, 9, 16]
# 带条件筛选
even = [x for x in range(10) if x % 2 == 0]
print(even) # [0, 2, 4, 6, 8]
# AI 实战:归一化数据到 [0, 1]
raw_scores = [10, 20, 30, 40, 50]
max_score = max(raw_scores)
normalized = [s / max_score for s in raw_scores]
print(normalized) # [0.2, 0.4, 0.6, 0.8, 1.0]
# 批量处理文本(NLP 预处理)
texts = ["Hello World", " Python ", "AI Dev"]
cleaned = [t.strip().lower() for t in texts]
print(cleaned) # ['hello world', 'python', 'ai dev']
dict —— 字典(键值对映射)
字典用 {} 定义,存储键(key)→ 值(value)的映射关系。就像真实的字典:通过词条(key)找到解释(value)。在 AI 开发中,字典是最重要的数据结构之一,API 请求、配置参数、模型结果都用字典表示。
# 创建字典:{ key: value, key: value, ... }
model_config = {
"model": "claude-sonnet-4-6",
"max_tokens": 1024,
"temperature": 0.7,
"stream": False
}
# 访问值(用 key 取 value)
print(model_config["model"]) # claude-sonnet-4-6
print(model_config["temperature"]) # 0.7
# 安全访问(不存在的 key 用 get,不会报错)
print(model_config.get("timeout")) # None(key不存在)
print(model_config.get("timeout", 30)) # 30(设置默认值)
# 添加/修改
model_config["top_p"] = 0.9 # 添加新键
model_config["temperature"] = 0.5 # 修改已有键
# 删除
del model_config["stream"] # 删除 key
val = model_config.pop("top_p") # 删除并返回值
# 查询
print("model" in model_config) # True(检查 key 是否存在)
print(model_config.keys()) # 所有 key
print(model_config.values()) # 所有 value
print(model_config.items()) # 所有 (key, value) 对
# LLM API 消息格式(最常见的字典用法)
messages = [
{"role": "system", "content": "你是一个 Python 专家"},
{"role": "user", "content": "如何学习 Python"}
]
# 模型训练结果统计
metrics = {
"train_loss": 0.23,
"val_loss": 0.31,
"accuracy": 0.94,
"f1_score": 0.92
}
# 遍历字典
for metric_name, value in metrics.items():
print(f"{metric_name}: {value}")
# train_loss: 0.23
# val_loss: 0.31 ...
# 字典推导式
raw = {"a": 1, "b": 2, "c": 3}
doubled = {k: v * 2 for k, v in raw.items()}
print(doubled) # {'a': 2, 'b': 4, 'c': 6}
# 合并字典(Python 3.9+)
base_config = {"model": "gpt-4o", "temperature": 0.7}
extra = {"max_tokens": 2048}
full_config = base_config | extra # 合并
tuple —— 元组(有序不可变)
元组用圆括号 () 定义,和列表类似,但不能修改(不可变)。一旦创建,元素就固定了。适合存储不应该被改变的数据,比如坐标、RGB 颜色值、图像尺寸。
# 创建元组
image_size = (224, 224, 3) # (高, 宽, 通道) 图像尺寸
point = (3.5, 2.1) # 2D 坐标
rgb = (255, 128, 0) # 橙色的 RGB 值
# 访问元素(和列表一样用索引)
print(image_size[0]) # 224(高度)
print(image_size[2]) # 3(通道数)
# 元组不能修改(这行会报错!)
# image_size[0] = 256 ← TypeError!
# 解包(unpack):把元组拆分成多个变量
height, width, channels = image_size
print(f"图像: {height}x{width}, {channels}通道")
# 函数返回多个值时,实际上是返回一个元组
def get_model_stats():
return 0.95, 0.23 # 返回 (accuracy, loss)
acc, loss = get_model_stats() # 解包接收
print(f"准确率: {acc}, 损失: {loss}")
set —— 集合(无序不重复)
集合用 {}(但里面没有键值对)定义,自动去除重复元素,无固定顺序。适合去重、快速判断元素是否存在、以及集合运算(交集、并集)。
# 创建集合(自动去重)
vocab = {"hello", "world", "hello", "python"}
print(vocab) # {'hello', 'world', 'python'}(去重了)
# 用列表创建集合(去重技巧)
labels = ["cat", "dog", "cat", "bird", "dog"]
unique_labels = set(labels) # {'cat', 'dog', 'bird'}
print(len(unique_labels)) # 3 个唯一类别
# 检查元素(速度比列表快很多)
print("cat" in unique_labels) # True
# 集合运算(在 NLP 词汇分析中常用)
vocab_a = {"apple", "banana", "cat"}
vocab_b = {"cat", "dog", "banana"}
print(vocab_a & vocab_b) # 交集:{'cat', 'banana'}(共有的)
print(vocab_a | vocab_b) # 并集:{'apple', 'banana', 'cat', 'dog'}
print(vocab_a - vocab_b) # 差集:{'apple'}(A 有 B 没有)
四种数据结构对比
| 类型 | 符号 | 有序 | 可修改 | 允许重复 | AI 中的典型用途 |
|---|---|---|---|---|---|
list |
[] |
✅ | ✅ | ✅ | 训练损失历史、消息列表、数据集 |
dict |
{k:v} |
✅(3.7+) | ✅ | key唯一 | API 参数、配置文件、模型输出 |
tuple |
() |
✅ | ❌ | ✅ | 图像尺寸、坐标、函数多返回值 |
set |
{} |
❌ | ✅ | ❌ | 词汇表、去重、类别标签集合 |
底层原理:为什么选这种结构?
了解数据结构的底层实现,能帮你在 AI 项目中做出更好的性能选择。
-
list 的内存布局
Python list 是动态数组,内存中连续存储元素引用(指针)。随机访问
list[i]是 O(1),尾部追加append()平均 O(1),中间插入insert(0, x)是 O(n)(需要移动所有元素)。AI 中收集训练损失时应用append()而非insert(0, x)。 -
dict 的哈希表实现
dict 底层是哈希表,key 查找是 O(1) 平均时间复杂度。这就是为什么
"key" in dict比"key" in list快——list 需要线性搜索 O(n)。Python 3.7+ 起 dict 保证插入顺序(有序字典)。 -
set 的哈希特性
set 也是基于哈希表,成员检查
x in set是 O(1),比 list 的 O(n) 快得多。NLP 中检查某词是否在词汇表时,应使用set而不是list。 -
tuple 的不可变优势
tuple 不可变,因此可以作为 dict 的 key(list 不行!),也可以被 set 包含。在 NumPy/PyTorch 中,
tensor.shape返回的就是 tuple,因为形状不应该被修改。
import time
# 成员检查:set vs list 的速度差距
vocab_list = list(range(100000)) # 10万词的词汇表(列表)
vocab_set = set(range(100000)) # 10万词的词汇表(集合)
# 查询 99999 是否在词汇表(最坏情况)
target = 99999
t0 = time.time()
for _ in range(10000):
target in vocab_list # O(n) 线性搜索
print(f"list: {time.time()-t0:.3f}s") # 约 3-4 秒
t0 = time.time()
for _ in range(10000):
target in vocab_set # O(1) 哈希查找
print(f"set: {time.time()-t0:.3f}s") # 约 0.001 秒,快 1000 倍!
# tuple 可以作为 dict 的 key
cache = {}
cache[(224, 224)] = "resnet50_features" # ✅ tuple 可以作 key
# cache[[224, 224]] = ... # ❌ list 不能作 key,会 TypeError
# 计数器(统计类别频率)
from collections import Counter
labels = ["cat", "dog", "cat", "bird", "cat", "dog"]
counts = Counter(labels)
print(counts) # Counter({'cat': 3, 'dog': 2, 'bird': 1})
print(counts.most_common(2)) # [('cat', 3), ('dog', 2)]
浅拷贝与深拷贝陷阱
列表赋值 b = a 只是复制了引用,a 和 b 指向同一个列表!修改 b 会影响 a。
浅拷贝:b = a.copy() 或 b = a[:],创建新列表但元素本身仍共享。
深拷贝:import copy; b = copy.deepcopy(a),完全独立。
在 AI 中复制配置字典时,务必使用 config.copy() 或 copy.deepcopy(config),否则修改副本会影响原始配置。
本章小结
Python 四种核心数据结构:list(有序可变,动态数组)、dict(键值映射,哈希表)、tuple(有序不可变)、set(无序不重复,哈希表)。选择原则:需要快速成员检查用 set;需要键值映射用 dict;数据顺序重要且需要修改用 list;不需要修改的序列用 tuple。AI 开发中 dict 是使用最频繁的结构,几乎所有 API 接口、配置和返回结果都是字典或字典的列表。注意浅拷贝与深拷贝的区别。