列表、字典、元组、集合:Python四大容器类型,一篇搞懂什么时候用哪个
容器类型是Python中最常用的数据结构,用于存储多个元素。掌握列表、元组、字典、集合的使用是Python编程的基础。本篇将详细介绍这四种容器类型的特性、操作方法,并与C语言的数组进行对比。
1. 容器类型概览
| 类型 | 有序 | 可变 | 可重复 | 索引方式 | 典型用途 |
|---|---|---|---|---|---|
| 列表 list | ✅ | ✅ | ✅ | 整数索引 | 存储有序数据集合 |
| 元组 tuple | ✅ | ❌ | ✅ | 整数索引 | 存储不可变的有序数据 |
| 字典 dict | ✅* | ✅ | 键不可重复 | 键索引 | 键值对映射 |
| 集合 set | ❌ | ✅ | ❌ | 无索引 | 去重、集合运算 |
*注:Python 3.7+字典保持插入顺序
2. 列表(list)
列表是Python中最常用的容器类型,类似于C语言的数组,但功能更强大。
2.1 列表的创建
# 空列表
empty_list = []
empty_list = list()
# 带初始值的列表
numbers = [1, 2, 3, 4, 5]
fruits = ["apple", "banana", "cherry"]
# 混合类型(Python允许,C不允许)
mixed = [1, "hello", 3.14, True, None]
# 从其他可迭代对象创建
from_string = list("hello") # ['h', 'e', 'l', 'l', 'o']
from_range = list(range(5)) # [0, 1, 2, 3, 4]
# 重复元素
zeros = [0] * 5 # [0, 0, 0, 0, 0]
pattern = [1, 2] * 3 # [1, 2, 1, 2, 1, 2]
2.2 列表的索引与切片
fruits = ["apple", "banana", "cherry", "date", "elderberry"]
# 索引访问
print(fruits[0]) # 'apple'(第一个)
print(fruits[-1]) # 'elderberry'(最后一个)
print(fruits[2]) # 'cherry'
# 修改元素
fruits[0] = "apricot"
print(fruits) # ['apricot', 'banana', 'cherry', 'date', 'elderberry']
# 切片 [start:end:step]
print(fruits[1:3]) # ['banana', 'cherry']
print(fruits[:3]) # ['apricot', 'banana', 'cherry']
print(fruits[2:]) # ['cherry', 'date', 'elderberry']
print(fruits[::2]) # ['apricot', 'cherry', 'elderberry']
print(fruits[::-1]) # 反转列表
# 切片赋值
fruits[1:3] = ["blueberry", "cantaloupe"]
print(fruits) # ['apricot', 'blueberry', 'cantaloupe', 'date', 'elderberry']
# 切片删除
fruits[1:3] = []
print(fruits) # ['apricot', 'date', 'elderberry']
2.3 列表的常用方法
# 添加元素
fruits = ["apple", "banana"]
fruits.append("cherry") # 末尾添加:['apple', 'banana', 'cherry']
fruits.insert(1, "apricot") # 指定位置插入:['apple', 'apricot', 'banana', 'cherry']
fruits.extend(["date", "elderberry"]) # 扩展列表
# 删除元素
fruits.remove("banana") # 按值删除(删除第一个匹配项)
item = fruits.pop() # 弹出末尾元素并返回
item = fruits.pop(0) # 弹出指定位置元素
del fruits[0] # 删除指定位置元素
fruits.clear() # 清空列表
# 查找元素
fruits = ["apple", "banana", "cherry", "banana"]
print(fruits.index("banana")) # 1(第一个匹配项的索引)
print(fruits.count("banana")) # 2(出现次数)
print("apple" in fruits) # True(是否存在)
# 排序
numbers = [3, 1, 4, 1, 5, 9, 2, 6]
numbers.sort() # 原地排序:[1, 1, 2, 3, 4, 5, 6, 9]
numbers.sort(reverse=True) # 降序排序
sorted_nums = sorted(numbers) # 返回新列表,原列表不变
# 自定义排序
words = ["banana", "apple", "Cherry"]
words.sort(key=str.lower) # 忽略大小写排序
words.sort(key=len) # 按长度排序
# 反转
numbers.reverse() # 原地反转
reversed_nums = numbers[::-1] # 返回新列表
# 复制
copy1 = fruits.copy() # 浅复制
copy2 = fruits[:] # 浅复制
copy3 = list(fruits) # 浅复制
import copy
deep_copy = copy.deepcopy(fruits) # 深复制(嵌套列表时使用)
2.4 列表推导式
列表推导式是Python的特色语法,可以简洁地创建列表。
# 基本语法:[表达式 for 变量 in 可迭代对象]
squares = [x**2 for x in range(10)]
# [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
# 带条件:[表达式 for 变量 in 可迭代对象 if 条件]
even_squares = [x**2 for x in range(10) if x % 2 == 0]
# [0, 4, 16, 36, 64]
# 多重循环
matrix = [[i*3+j for j in range(3)] for i in range(3)]
# [[0, 1, 2], [3, 4, 5], [6, 7, 8]]
# 展平嵌套列表
nested = [[1, 2], [3, 4], [5, 6]]
flat = [x for sublist in nested for x in sublist]
# [1, 2, 3, 4, 5, 6]
# 条件表达式
numbers = [1, -2, 3, -4, 5]
abs_nums = [x if x > 0 else -x for x in numbers]
# [1, 2, 3, 4, 5]
# 与传统循环对比
# 传统写法
squares = []
for x in range(10):
squares.append(x**2)
# 列表推导式
squares = [x**2 for x in range(10)]
2.5 列表与C数组对比
| 特性 | C数组 | Python列表 |
|---|---|---|
| 类型 | 固定类型 | 可混合类型 |
| 大小 | 固定大小 | 动态大小 |
| 内存 | 连续内存 | 对象引用数组 |
| 越界 | 未定义行为 | 抛出异常 |
| 操作 | 手动实现 | 内置方法丰富 |
// C数组
int arr[5] = {1, 2, 3, 4, 5};
arr[0] = 10;
// 无法直接添加元素,需要重新分配内存
# Python列表
arr = [1, 2, 3, 4, 5]
arr[0] = 10
arr.append(6) # 轻松添加元素
3. 元组(tuple)
元组是不可变的有序序列,一旦创建就不能修改。
3.1 元组的创建
# 空元组
empty_tuple = ()
empty_tuple = tuple()
# 带初始值的元组
point = (3, 4)
colors = ("red", "green", "blue")
# 单元素元组(注意逗号)
single = (1,) # 正确:元组
not_tuple = (1) # 错误:这是整数1
# 省略括号
point = 3, 4 # 等价于 (3, 4)
a, b = 1, 2 # 元组解包
# 从其他可迭代对象创建
from_list = tuple([1, 2, 3])
from_string = tuple("hello") # ('h', 'e', 'l', 'l', 'o')
3.2 元组的特性
point = (3, 4, 5)
# 索引和切片(与列表相同)
print(point[0]) # 3
print(point[-1]) # 5
print(point[1:]) # (4, 5)
# 不可变性
# point[0] = 10 # TypeError: 'tuple' object does not support item assignment
# 元组方法(只有两个)
print(point.count(3)) # 1
print(point.index(4)) # 1
# 元组解包
x, y, z = point
print(x, y, z) # 3 4 5
# 扩展解包(Python 3)
first, *rest = (1, 2, 3, 4, 5)
print(first) # 1
print(rest) # [2, 3, 4, 5]
*start, last = (1, 2, 3, 4, 5)
print(start) # [1, 2, 3, 4]
print(last) # 5
# 元组拼接(创建新元组)
t1 = (1, 2)
t2 = (3, 4)
t3 = t1 + t2 # (1, 2, 3, 4)
3.3 元组的应用场景
# 1. 函数返回多个值
def get_min_max(numbers):
return min(numbers), max(numbers)
min_val, max_val = get_min_max([3, 1, 4, 1, 5])
# 2. 交换变量
a, b = 10, 20
a, b = b, a # 利用元组解包交换
# 3. 作为字典的键(列表不能作为键)
locations = {
(0, 0): "origin",
(1, 0): "right",
(0, 1): "up"
}
# 4. 保护数据不被修改
WEEKDAYS = ("Monday", "Tuesday", "Wednesday", "Thursday", "Friday")
# 5. 命名元组(更清晰的数据结构)
from collections import namedtuple
Point = namedtuple('Point', ['x', 'y'])
p = Point(3, 4)
print(p.x, p.y) # 3 4
print(p[0], p[1]) # 3 4
4. 字典(dict)
字典是键值对的集合,类似于C语言中的哈希表或其他语言的Map。
4.1 字典的创建
# 空字典
empty_dict = {}
empty_dict = dict()
# 带初始值的字典
person = {
"name": "张三",
"age": 25,
"city": "北京"
}
# 使用dict()构造
person = dict(name="张三", age=25, city="北京")
# 从键值对列表创建
items = [("name", "张三"), ("age", 25)]
person = dict(items)
# 使用fromkeys创建
keys = ["a", "b", "c"]
d = dict.fromkeys(keys, 0) # {'a': 0, 'b': 0, 'c': 0}
4.2 字典的操作
person = {"name": "张三", "age": 25, "city": "北京"}
# 访问值
print(person["name"]) # '张三'
print(person.get("name")) # '张三'
print(person.get("salary", 0)) # 0(键不存在时返回默认值)
# 修改值
person["age"] = 26
# 添加键值对
person["salary"] = 10000
# 删除键值对
del person["city"]
salary = person.pop("salary") # 删除并返回值
person.pop("unknown", None) # 键不存在时返回默认值
# 检查键是否存在
print("name" in person) # True
print("city" in person) # False
# 遍历字典
for key in person:
print(key, person[key])
for key, value in person.items():
print(f"{key}: {value}")
for key in person.keys():
print(key)
for value in person.values():
print(value)
4.3 字典的常用方法
d = {"a": 1, "b": 2}
# 获取所有键、值、键值对
keys = d.keys() # dict_keys(['a', 'b'])
values = d.values() # dict_values([1, 2])
items = d.items() # dict_items([('a', 1), ('b', 2)])
# 更新字典
d.update({"c": 3, "d": 4})
d.update(e=5, f=6)
# 设置默认值
d.setdefault("g", 7) # 如果键不存在,设置并返回默认值
# 合并字典(Python 3.9+)
d1 = {"a": 1, "b": 2}
d2 = {"c": 3, "d": 4}
d3 = d1 | d2 # {'a': 1, 'b': 2, 'c': 3, 'd': 4}
# Python 3.5+的合并方式
d3 = {**d1, **d2}
# 复制
d_copy = d.copy() # 浅复制
# 清空
d.clear()
4.4 字典推导式
# 基本语法:{键表达式: 值表达式 for 变量 in 可迭代对象}
squares = {x: x**2 for x in range(5)}
# {0: 0, 1: 1, 2: 4, 3: 9, 4: 16}
# 带条件
even_squares = {x: x**2 for x in range(10) if x % 2 == 0}
# {0: 0, 2: 4, 4: 16, 6: 36, 8: 64}
# 键值互换
original = {"a": 1, "b": 2, "c": 3}
swapped = {v: k for k, v in original.items()}
# {1: 'a', 2: 'b', 3: 'c'}
# 从两个列表创建字典
keys = ["name", "age", "city"]
values = ["张三", 25, "北京"]
person = {k: v for k, v in zip(keys, values)}
# 或使用dict(zip(keys, values))
5. 集合(set)
集合是无序、不重复元素的集合,支持数学集合运算。
5.1 集合的创建
# 空集合(注意:{}是空字典)
empty_set = set()
# 带初始值的集合
numbers = {1, 2, 3, 4, 5}
fruits = {"apple", "banana", "cherry"}
# 自动去重
numbers = {1, 2, 2, 3, 3, 3}
print(numbers) # {1, 2, 3}
# 从其他可迭代对象创建
from_list = set([1, 2, 2, 3]) # {1, 2, 3}
from_string = set("hello") # {'h', 'e', 'l', 'o'}
# 不可变集合
frozen = frozenset([1, 2, 3])
5.2 集合的操作
# 添加元素
s = {1, 2, 3}
s.add(4) # {1, 2, 3, 4}
s.update([5, 6]) # {1, 2, 3, 4, 5, 6}
# 删除元素
s.remove(6) # 删除指定元素(不存在则报错)
s.discard(10) # 删除指定元素(不存在不报错)
item = s.pop() # 随机弹出一个元素
s.clear() # 清空集合
# 集合运算
a = {1, 2, 3, 4}
b = {3, 4, 5, 6}
# 并集
print(a | b) # {1, 2, 3, 4, 5, 6}
print(a.union(b))
# 交集
print(a & b) # {3, 4}
print(a.intersection(b))
# 差集
print(a - b) # {1, 2}
print(a.difference(b))
# 对称差集(异或)
print(a ^ b) # {1, 2, 5, 6}
print(a.symmetric_difference(b))
# 子集和超集
c = {1, 2}
print(c <= a) # True(c是a的子集)
print(c.issubset(a))
print(a >= c) # True(a是c的超集)
print(a.issuperset(c))
# 不相交
d = {7, 8}
print(a.isdisjoint(d)) # True(没有共同元素)
5.3 集合的应用场景
# 1. 去重
numbers = [1, 2, 2, 3, 3, 3, 4, 4, 4, 4]
unique = list(set(numbers)) # [1, 2, 3, 4]
# 2. 成员检测(比列表快)
valid_users = {"alice", "bob", "charlie"}
if "alice" in valid_users:
print("用户有效")
# 3. 找出两个列表的共同元素
list1 = [1, 2, 3, 4, 5]
list2 = [4, 5, 6, 7, 8]
common = set(list1) & set(list2) # {4, 5}
# 4. 找出两个列表的不同元素
diff = set(list1) ^ set(list2) # {1, 2, 3, 6, 7, 8}
# 5. 统计唯一元素个数
text = "hello world"
unique_chars = len(set(text)) # 8(包括空格)
6. 容器类型对比
| 操作 | 列表 list | 元组 tuple | 字典 dict | 集合 set |
|---|---|---|---|---|
| 创建 | [1, 2] | (1, 2) | {"a": 1} | {1, 2} |
| 空容器 | [] | () | {} | set() |
| 添加 | append() | 不可变 | d[k]=v | add() |
| 删除 | remove() | 不可变 | del d[k] | remove() |
| 访问 | lst[i] | tup[i] | d[k] | 无索引 |
| 长度 | len() | len() | len() | len() |
| 遍历 | for x in | for x in | for k in | for x in |
| 成员检测 | in(慢) | in(慢) | in(快) | in(快) |
选择建议:
| 需求 | 推荐类型 |
|---|---|
| 有序、可修改的数据集合 | 列表 |
| 有序、不可修改的数据 | 元组 |
| 键值对映射 | 字典 |
| 去重、集合运算 | 集合 |
| 函数返回多个值 | 元组 |
| 作为字典的键 | 元组(不可变) |
| 快速成员检测 | 集合或字典 |
7. 嵌套与复杂数据结构
# 嵌套列表(二维数组/矩阵)
matrix = [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9]
]
print(matrix[1][2]) # 6
# 列表中的字典
students = [
{"name": "张三", "score": 85},
{"name": "李四", "score": 92},
{"name": "王五", "score": 78}
]
print(students[0]["name"]) # 张三
# 字典中的列表
class_info = {
"class_name": "一班",
"students": ["张三", "李四", "王五"],
"scores": [85, 92, 78]
}
# 字典中的字典
company = {
"name": "ABC公司",
"departments": {
"tech": {"head": "张三", "count": 20},
"sales": {"head": "李四", "count": 15}
}
}
print(company["departments"]["tech"]["head"]) # 张三
# 实际应用:JSON数据结构
user_data = {
"id": 1001,
"name": "张三",
"contacts": {
"email": "[email protected]",
"phone": ["13800138000", "13900139000"]
},
"orders": [
{"id": "A001", "amount": 100.0},
{"id": "A002", "amount": 200.0}
]
}
8. 常见错误与避坑
❌ 错误1:列表作为默认参数
# 错误:可变对象作为默认参数
def add_item(item, lst=[]):
lst.append(item)
return lst
print(add_item(1)) # [1]
print(add_item(2)) # [1, 2](不是[2]!)
# 正确:使用None作为默认值
def add_item(item, lst=None):
if lst is None:
lst = []
lst.append(item)
return lst
❌ 错误2:浅复制陷阱
# 浅复制:嵌套对象共享引用
original = [[1, 2], [3, 4]]
shallow = original.copy()
shallow[0][0] = 100
print(original) # [[100, 2], [3, 4]](原列表也被修改!)
# 深复制:完全独立
import copy
deep = copy.deepcopy(original)
deep[0][0] = 999
print(original) # [[100, 2], [3, 4]](原列表不变)
❌ 错误3:遍历时修改列表
# 错误:遍历时删除元素
numbers = [1, 2, 3, 4, 5]
for n in numbers:
if n % 2 == 0:
numbers.remove(n) # 可能跳过元素
# 正确:遍历副本或使用列表推导式
numbers = [1, 2, 3, 4, 5]
numbers = [n for n in numbers if n % 2 != 0]
❌ 错误4:字典键不存在
d = {"a": 1}
# 错误:直接访问不存在的键
# print(d["b"]) # KeyError
# 正确:使用get()或检查
print(d.get("b", 0)) # 0
if "b" in d:
print(d["b"])
❌ 错误5:集合元素必须可哈希
# 错误:列表不能作为集合元素
# s = {[1, 2], [3, 4]} # TypeError
# 正确:使用元组
s = {(1, 2), (3, 4)}
9. 实战练习
练习1:列表操作
"""
练习:学生成绩管理
"""
scores = [85, 92, 78, 96, 88, 73, 91, 82]
# 1. 计算平均分
average = sum(scores) / len(scores)
print(f"平均分:{average:.2f}")
# 2. 找出最高分和最低分
print(f"最高分:{max(scores)}")
print(f"最低分:{min(scores)}")
# 3. 统计及格人数(>=60)
pass_count = len([s for s in scores if s >= 60])
print(f"及格人数:{pass_count}")
# 4. 按成绩排序
sorted_scores = sorted(scores, reverse=True)
print(f"成绩排名:{sorted_scores}")
练习2:字典操作
"""
练习:单词频率统计
"""
text = "hello world hello python world python python"
words = text.split()
# 统计词频
word_count = {}
for word in words:
word_count[word] = word_count.get(word, 0) + 1
print(word_count)
# {'hello': 2, 'world': 2, 'python': 3}
# 使用Counter(更简洁)
from collections import Counter
word_count = Counter(words)
print(word_count.most_common(2)) # [('python', 3), ('hello', 2)]
练习3:集合操作
"""
练习:找出两个班级的共同学生和各自独有学生
"""
class_a = {"张三", "李四", "王五", "赵六", "钱七"}
class_b = {"王五", "赵六", "孙八", "周九", "吴十"}
# 共同学生
common = class_a & class_b
print(f"共同学生:{common}")
# A班独有
only_a = class_a - class_b
print(f"A班独有:{only_a}")
# B班独有
only_b = class_b - class_a
print(f"B班独有:{only_b}")
# 所有学生
all_students = class_a | class_b
print(f"所有学生:{all_students}")
10. 总结
🔑 核心要点
| 知识点 | 要点 |
|---|---|
| 列表 | 有序可变,支持索引切片,方法丰富 |
| 元组 | 有序不可变,可作为字典键 |
| 字典 | 键值对映射,键必须可哈希 |
| 集合 | 无序不重复,支持集合运算 |
| 推导式 | 简洁创建列表/字典/集合 |
| 深浅复制 | 嵌套结构需注意深复制 |
✅ 学习检查清单
- 掌握列表的创建、索引、切片、常用方法
- 理解列表推导式的语法
- 理解元组的不可变性和应用场景
- 掌握字典的创建和操作
- 掌握集合的创建和集合运算
- 理解深浅复制的区别
- 能根据需求选择合适的容器类型
📖 下一步学习
掌握了容器类型后,让我们学习Python的运算符与表达式:
常见问题 FAQ
💬 列表和元组怎么选?
需要修改用列表,不需要修改用元组。元组更省内存、可以做字典的key、作为函数返回多个值很方便。
💬 字典是有序的吗?
Python 3.7+字典保持插入顺序。但如果你需要排序功能,用collections.OrderedDict更明确。
📘 系列导航
- 上一篇:04 - Python数据类型详解
- 当前:05 - Python容器类型详解
- 下一篇:06 - Python运算符与表达式 📝 作者:Python学习助手 🔄 最后更新:2025-12-18