单个变量只能保存一个对象,而真实程序通常需要处理一组数据。Python 提供了列表、字典、元组和集合等容器类型,分别适用于顺序存储、键值映射、固定数据和去重查询等场景。本文重点复盘列表与字典,并对四类容器进行比较。

一、什么是容器

容器是能够同时保存多个数据的对象。例如,记录五名学生的成绩时,如果分别创建五个变量,后续统计和遍历会很麻烦:

score_1 = 88
score_2 = 92
score_3 = 75

使用列表可以把同类数据集中管理:

scores = [88, 92, 75]

Python 中常见的四种容器如下:

容器主要特点适用场景
list有序、可变、可重复按顺序保存一组数据
dict键值映射、键唯一根据名称或编号查找信息
tuple有序、不可变保存不应被修改的数据
set无重复元素、快速查询去重、成员判断、集合运算

二、列表的创建与索引

列表使用方括号创建,可以保存不同类型的数据:

numbers = [10, 20, 30]
mixed = [1, "Python", True]
empty = []

还可以使用 list() 将其他可迭代对象转换为列表:

numbers = list(range(5))  # [0, 1, 2, 3, 4]
letters = list("abc")     # ["a", "b", "c"]

列表索引从 0 开始,负数索引表示从末尾向前查找:

scores = [88, 92, 75, 60, 100]

print(scores[0])   # 88
print(scores[-1])  # 100
print(scores[-2])  # 60
print(len(scores)) # 5

长度为 5 的列表,最大正索引是 4。访问 scores[5] 会触发 IndexError。获取最后一个元素时,推荐直接使用 scores[-1]

三、列表的增删改查

列表是可变容器,创建后可以继续修改。

1. 添加元素

numbers = [1, 2, 3]

numbers.append(4)        # 末尾添加一个元素
numbers.insert(0, 0)     # 在指定位置插入
numbers.extend([5, 6])   # 批量添加多个元素

append()extend() 容易混淆:

data = [1, 2]
data.append([3, 4])  # [1, 2, [3, 4]]

data = [1, 2]
data.extend([3, 4])  # [1, 2, 3, 4]

append() 把整个对象作为一个元素加入列表;extend() 则依次加入另一个可迭代对象中的元素。

2. 删除元素

numbers = [10, 20, 30, 20]

numbers.remove(20)  # 按值删除第一个 20
last = numbers.pop()  # 删除并返回最后一个元素
del numbers[0]      # 按索引删除
numbers.clear()     # 清空列表

remove(x) 在找不到元素时会触发 ValueError,可以先使用 x in numbers 判断。pop() 会返回被删除的元素,适合“取出并删除”的场景。

3. 修改与查询

scores = [88, 92, 75]

scores[1] = 95
print(88 in scores)       # True
print(scores.index(75))   # 2
print(scores.count(88))   # 1

index() 返回元素第一次出现的位置,找不到时会报错;count() 用于统计元素出现次数。

四、列表切片

切片可以一次获取列表中的一段数据,基本语法为:

列表[起始位置:结束位置:步长]

切片遵循“包含起始位置、不包含结束位置”的左闭右开规则:

numbers = list(range(10))

print(numbers[2:5])   # [2, 3, 4]
print(numbers[:3])    # [0, 1, 2]
print(numbers[-3:])   # [7, 8, 9]
print(numbers[::2])   # [0, 2, 4, 6, 8]
print(numbers[::-1])  # 反转列表

切片会创建一个浅拷贝:

original = [1, 2, 3]
copy_list = original[:]
copy_list[0] = 99

print(original)  # [1, 2, 3]

copy_list = original 只是让两个变量引用同一个列表,通过任意一个变量修改内容都会影响另一个变量。需要注意,浅拷贝只能复制外层容器,嵌套的可变对象仍可能被共享。

五、字典:通过键查找值

列表按照位置访问数据,字典则按照键访问对应的值:

scores = {
    "张三": 88,
    "李四": 92,
    "王五": 75,
}

print(scores["张三"])  # 88

字典适合通讯录、配置项、商品信息和学生成绩等“名称—数据”映射场景。

字典的键必须是可哈希对象,字符串、整数以及只包含可哈希元素的元组通常可以作为键;列表、字典和集合不能作为键。键不能重复,重复赋值会覆盖原来的值。

六、字典的增删改查

为字典赋值时,键不存在表示新增,键已存在表示修改:

scores = {"张三": 88}

scores["李四"] = 92  # 新增
scores["张三"] = 90  # 修改

读取字典值有两种常见方式:

print(scores["张三"])
print(scores.get("赵六"))
print(scores.get("赵六", 0))

使用方括号访问不存在的键会触发 KeyErrorget() 可以返回 None 或指定的默认值,因此在不确定键是否存在时更加安全。不过,如果缺少该键本身代表数据错误,直接使用方括号也能帮助程序尽早暴露问题。

删除字典元素可以使用 delpop()

data = {"a": 1, "b": 2}

del data["a"]
value = data.pop("b")
missing = data.pop("c", None)

批量合并字典可以使用 update()。如果两个字典包含相同的键,新值会覆盖旧值:

config = {"theme": "light", "font_size": 14}
config.update({"theme": "dark", "language": "zh"})

七、字典遍历

字典可以分别遍历键、值或键值对:

scores = {"张三": 88, "李四": 92}

for name in scores:
    print(name)

for score in scores.values():
    print(score)

for name, score in scores.items():
    print(f"{name}考了{score}分")

实际开发中,items() 是最常用的遍历方式,因为它可以同时得到键和值。

八、元组与集合

元组与列表相似,但创建后不能修改:

point = (3, 4)
print(point[0])

single = (5,)  # 单元素元组必须保留逗号

坐标、RGB 颜色等固定数据适合使用元组。元组还可以在满足可哈希条件时作为字典的键。

集合主要用于去重和成员判断:

names = ["张三", "李四", "张三", "王五"]
unique_names = set(names)

print("张三" in unique_names)  # True

集合还支持交集、并集和差集:

a = {1, 2, 3}
b = {3, 4, 5}

print(a & b)  # {3}
print(a | b)  # {1, 2, 3, 4, 5}
print(a - b)  # {1, 2}

列表的成员查找平均需要逐个比较,时间复杂度为 O(n);字典按键查找和集合成员判断的平均时间复杂度通常为 O(1)。因此,当数据量较大且需要频繁判断元素是否存在时,集合通常比列表更合适。

九、嵌套容器

真实数据经常由多层容器组成。例如,可以用列表保存多名学生,再用字典描述每名学生:

students = [
    {"name": "张三", "score": 88},
    {"name": "李四", "score": 92},
    {"name": "王五", "score": 75},
]

print(students[0]["score"])  # 88

for student in students:
    print(student["name"])

best = max(students, key=lambda student: student["score"])
print(best)

students[0]["score"] 包含两层访问:先从列表中取出第一个字典,再通过 "score" 获取对应值。理解这种逐层访问方式,是后续处理 JSON、接口响应和数据集的基础。

十、如何选择容器

需求推荐容器
数据有顺序、允许重复且需要修改list
根据名称或编号查找数据dict
数据固定不变tuple
去重或频繁判断成员是否存在set

可以用三个问题帮助选择:数据是否需要修改?是否需要通过名称查值?是否主要用于去重或成员判断?

总结

列表适合有序数据,字典适合键值映射,元组适合固定数据,集合适合去重和快速查询。掌握容器时,不仅要会调用方法,还要理解每种结构的数据组织方式。

需要重点区分:

  1. append() 添加一个对象,extend() 批量添加元素;

  2. remove() 按值删除,pop()del 可以按位置删除;

  3. 切片左闭右开,[::-1] 可以反转序列;

  4. 字典的 [] 访问可能触发 KeyErrorget() 可以设置默认值;

  5. b = a 共享同一个列表,b = a[:] 创建浅拷贝;

  6. 大量成员查询和去重任务优先考虑集合。

建议通过学生成绩、通讯录、词频统计和名单去重等小案例反复练习,逐渐形成根据业务需求选择容器的习惯。

更多推荐