Python容器从列表、元组、集合到字典,重点掌握dict示例详解
作者:刚哥带你学AI
一、什么是 Python 容器?
在 Python 开发中,我们经常需要存储和处理一组数据。例如,保存用户列表、记录商品价格、统计文章访问量、管理数据库查询结果等。
如果每个数据都使用一个独立变量保存,不仅代码繁琐,而且不方便进行批量操作。Python 提供了多种内置容器类型,用于组织和管理多个数据。
Python 中最常用的四种内置容器是:
| 容器类型 | 英文名称 | 特点 | 是否可变 |
|---|---|---|---|
| 列表 | list | 有序、允许重复 | 是 |
| 元组 | tuple | 有序、允许重复 | 否 |
| 集合 | set | 元素唯一、不保证固定遍历顺序 | 是 |
| 字典 | dict | 键值对存储,键唯一 | 是 |
此外,Python 还有字符串 str、字节序列 bytes 等序列类型。它们也可以用于存储和处理数据,但用途与上述容器有所不同。
下面分别介绍这些容器的使用方法,重点讲解实际开发中使用频率非常高的字典。
二、列表 list:有序的数据集合
列表是 Python 中最常用的容器之一,适合存储一组需要按顺序访问的数据。
2.1 创建列表
# 直接创建 numbers = [1, 2, 3, 4, 5] # 允许重复元素 names = ["张三", "李四", "张三"] # 不同类型的数据可以混合存储 data = [1, "Python", True, 3.14] # 创建空列表 items = [] # 使用 list() 转换 values = list(range(5)) print(values) # [0, 1, 2, 3, 4]
2.2 列表的常用操作
fruits = ["苹果", "香蕉", "橙子"]
# 添加元素
fruits.append("葡萄")
# 在指定位置插入元素
fruits.insert(1, "西瓜")
# 删除指定元素,删除第一个匹配项
fruits.remove("香蕉")
# 根据索引删除并返回元素
item = fruits.pop(0)
# 修改元素
fruits[0] = "芒果"
# 获取长度
print(len(fruits))
# 判断元素是否存在
print("橙子" in fruits)常用方法总结:
append():在末尾添加一个元素。extend():将另一个可迭代对象中的元素逐个追加。insert():在指定索引位置插入元素。remove():删除第一个匹配的元素。pop():删除并返回指定位置的元素。sort():对列表进行原地排序。reverse():原地反转列表。
2.3 列表切片
切片可以快速获取列表中的一部分数据。
numbers = [10, 20, 30, 40, 50, 60] print(numbers[1:4]) # [20, 30, 40] print(numbers[:3]) # [10, 20, 30] print(numbers[3:]) # [40, 50, 60] print(numbers[::2]) # [10, 30, 50] print(numbers[::-1]) # 倒序列表
切片的基本格式为:
list[start:stop:step]
其中,start 是起始索引,stop 是结束位置但不包含该位置,step 是步长。
2.4 列表推导式
列表推导式可以用简洁的方式创建新列表。
# 生成 0 到 9 的平方 squares = [x ** 2 for x in range(10)] # 筛选偶数 even_numbers = [x for x in range(20) if x % 2 == 0] # 对字符串进行转换 names = ["alice", "bob", "tom"] upper_names = [name.upper() for name in names] print(even_numbers) print(upper_names)
当数据转换和筛选逻辑比较简单时,列表推导式通常比普通循环更简洁。
三、元组 tuple:不可变的数据集合
元组与列表类似,也是一种有序容器,但元组创建后不能直接增删或替换其中的元素。
3.1 创建元组
point = (10, 20)
user = ("张三", 25, "北京")
# 单元素元组必须带逗号
single = (10,)
# 不带括号也可以创建元组
coordinates = 10, 20
# 创建空元组
empty = ()需要特别注意:
a = (10) b = (10,) print(type(a)) # <class 'int'> print(type(b)) # <class 'tuple'>
3.2 元组的常用操作
person = ("张三", 25, "北京")
print(person[0])
print(person[1:])
print(len(person))
# 解包
name, age, city = person
# 扩展解包
first, *middle, last = (1, 2, 3, 4, 5)
print(name, age, city)
print(middle) # [2, 3, 4]元组经常用于:
保存固定结构的数据。
函数返回多个结果。
表示坐标、日期等固定字段。
作为字典的键(前提是其中所有元素都可哈希)。
需要注意,元组的不可变性不意味着内部对象一定不可变。如果元组中包含列表,列表自身仍然可以修改。
data = ([1, 2], 3) data[0].append(4) print(data) # ([1, 2, 4], 3)
四、集合 set:去重与集合运算
集合中的元素必须唯一,适合去重、判断成员关系,以及执行交集、并集和差集等操作。
4.1 创建集合
numbers = {1, 2, 3, 4}
# 自动去重
values = {1, 2, 2, 3, 3}
# 创建空集合
empty_set = set()
print(values) # {1, 2, 3}注意:{} 创建的是空字典,而不是空集合。
4.2 集合常用方法
numbers = {1, 2, 3}
numbers.add(4)
numbers.update([5, 6, 7])
numbers.remove(2) # 元素不存在时会抛出 KeyError
numbers.discard(10) # 元素不存在时不会报错
item = numbers.pop() # 移除并返回一个元素4.3 集合运算
a = {1, 2, 3, 4}
b = {3, 4, 5, 6}
# 并集:属于任意一个集合
print(a | b)
# 交集:同时属于两个集合
print(a & b)
# 差集:属于 a,但不属于 b
print(a - b)
# 对称差集:只属于其中一个集合
print(a ^ b)集合常见应用包括用户去重、标签去重、权限比较,以及快速判断某个元素是否存在。
五、字典 dict:Python 最重要的容器之一
字典是 Python 中非常重要的数据结构。与列表通过索引访问元素不同,字典通过键 key 获取对应的值 value。
例如,保存用户信息:
user = {
"name": "张三",
"age": 25,
"city": "北京"
}
print(user["name"]) # 张三
print(user["age"]) # 25字典可以理解为一张映射表:
| Key(键) | Value(值) |
|---|---|
| name | 张三 |
| age | 25 |
| city | 北京 |
字典的主要特点:
使用键值对组织数据。
键必须唯一,重复的键会覆盖之前的值。
键必须是可哈希对象,常见的字符串、整数以及满足条件的元组都可以作为键。
值可以是任意 Python 对象,包括列表、元组、集合以及另一个字典。
Python 3.7 及之后的语言规范保证字典按照插入顺序迭代。
字典支持动态添加、修改和删除键值对。
5.1 字典的创建方式
方式一:直接创建
user = {
"name": "张三",
"age": 25,
"is_active": True
}方式二:使用 dict()
user = dict(name="张三", age=25, city="北京") print(user)
这种写法要求参数名符合 Python 标识符规则,适合键名比较简单的场景。
方式三:通过键值对序列创建
data = [
("name", "张三"),
("age", 25),
("city", "北京")
]
user = dict(data)
print(user)方式四:使用 fromkeys()
keys = ["name", "age", "city"]
user = dict.fromkeys(keys, None)
print(user)
# {'name': None, 'age': None, 'city': None}需要注意:如果默认值是可变对象,所有键可能引用同一个对象。
data = dict.fromkeys(["a", "b"], [])
data["a"].append(1)
print(data)
# {'a': [1], 'b': [1]}因为两个键对应的都是同一个列表。如果希望每个键对应独立列表,可以使用字典推导式:
data = {key: [] for key in ["a", "b"]}5.2 字典的增删改查
这是字典最基础、也最常用的操作。
添加和修改
user = {"name": "张三", "age": 25}
# 新增键值对
user["city"] = "北京"
# 修改已有值
user["age"] = 26
print(user)使用 user[key] = value 时,如果键存在就修改,不存在就新增。
查询元素
user = {"name": "张三", "age": 25}
print(user["name"])
# 键不存在时返回默认值
print(user.get("email", "未填写"))这里有一个非常重要的区别:
user = {"name": "张三"}
print(user.get("age")) # None
print(user.get("age", 0)) # 0
# user["age"] 会抛出 KeyError实际开发中,如果无法保证键一定存在,优先考虑 get(),能够减少异常处理代码。
但如果需要明确判断键是否存在,不能简单地把 get() 返回 None 当作不存在,因为字典中的值本身也可能是 None。
data = {"name": None}
print("name" in data) # True
print("age" in data) # False删除元素
user = {
"name": "张三",
"age": 25,
"city": "北京"
}
# 删除指定键
del user["age"]
# 删除并返回值
city = user.pop("city")
# 不存在时返回默认值
email = user.pop("email", None)
# 删除并返回最后插入的键值对
key, value = user.popitem()
# 清空字典
user.clear()注意:popitem() 在现代 Python 中移除的是最后插入的键值对,而不是随机删除。
5.3 字典的常用方法
| 方法 | 用途 | 示例 |
|---|---|---|
get() | 获取值,可设置默认值 | d.get("age", 0) |
keys() | 获取所有键 | d.keys() |
values() | 获取所有值 | d.values() |
items() | 获取键值对视图 | d.items() |
update() | 批量更新字典 | d.update(other) |
setdefault() | 键不存在时设置默认值 | d.setdefault("age", 0) |
pop() | 删除指定键并返回值 | d.pop("age", None) |
popitem() | 删除最后插入的键值对 | d.popitem() |
copy() | 创建浅拷贝 | d.copy() |
clear() | 清空字典 | d.clear() |
update():批量更新
user = {
"name": "张三",
"age": 25
}
user.update({
"age": 26,
"city": "北京"
})
print(user)
# {'name': '张三', 'age': 26, 'city': '北京'}如果更新数据中存在相同的键,新值会覆盖旧值。
setdefault():设置默认值
user = {"name": "张三"}
age = user.setdefault("age", 18)
print(age) # 18
print(user) # {'name': '张三', 'age': 18}如果键已经存在,setdefault() 不会覆盖原有值,而是返回现有值。
5.4 字典遍历
字典遍历在数据处理、接口开发和业务逻辑中非常常见。
遍历所有键
user = {
"name": "张三",
"age": 25,
"city": "北京"
}
for key in user:
print(key)也可以写成:
for key in user.keys():
print(key)一般来说,直接遍历字典即可,没有必要专门调用 keys()。
遍历所有值
for value in user.values():
print(value)同时遍历键和值
for key, value in user.items():
print(f"{key}: {value}")items() 是实际开发中最常用的字典遍历方法之一,因为它可以同时获取键和值。
例如,统计商品库存:
inventory = {
"苹果": 100,
"香蕉": 80,
"橙子": 60
}
for product, count in inventory.items():
print(f"{product} 剩余库存:{count}")5.5 字典推导式
字典推导式能够快速构建、转换和筛选字典。
基本格式:
{key表达式: value表达式 for item in iterable}示例一:创建字典
squares = {
x: x ** 2
for x in range(1, 6)
}
print(squares)
# {1: 1, 2: 4, 3: 9, 4: 16, 5: 25}示例二:筛选字典
scores = {
"张三": 85,
"李四": 58,
"王五": 92,
"赵六": 65
}
passed = {
name: score
for name, score in scores.items()
if score >= 60
}
print(passed)示例三:转换字典中的值
prices = {
"apple": 10,
"banana": 5,
"orange": 8
}
discount_prices = {
name: price * 0.8
for name, price in prices.items()
}
print(discount_prices)字典推导式特别适合数据映射、字段转换、过滤无效数据等场景。
5.6 字典合并
在实际开发中,经常需要合并配置文件、用户参数和默认配置。
Python 提供了多种方式。
方式一:使用 update()
default_config = {
"host": "127.0.0.1",
"port": 8000,
"debug": False
}
user_config = {
"port": 9000,
"debug": True
}
default_config.update(user_config)
print(default_config)这种方式会直接修改原字典。
方式二:使用 | 运算符
Python 3.9 及之后版本支持:
default_config = {
"host": "127.0.0.1",
"port": 8000
}
user_config = {
"port": 9000,
"debug": True
}
config = default_config | user_config
print(config)这种方式会生成新的字典,不修改原字典。发生键冲突时,右侧字典的值优先。
方式三:使用字典解包
config = {
**default_config,
**user_config
}字典解包适合在创建新字典时合并多个数据源,也可以同时添加额外字段:
config = {
**default_config,
**user_config,
"version": "1.0"
}5.7 字典排序
虽然字典按照插入顺序迭代,但它并不会自动按照键或值排序。
需要排序时,可以使用 sorted()。
按键排序
scores = {
"王五": 92,
"张三": 85,
"李四": 78
}
result = dict(sorted(scores.items()))
print(result)默认按照键进行升序排序。
按值排序
scores = {
"王五": 92,
"张三": 85,
"李四": 78
}
result = dict(
sorted(
scores.items(),
key=lambda item: item[1]
)
)
print(result)按值降序排序
result = dict(
sorted(
scores.items(),
key=lambda item: item[1],
reverse=True
)
)这里的 lambda item: item[1] 表示按照每个键值对中的第二个元素,也就是值进行排序。
需要注意,sorted() 返回的是列表,使用 dict() 转换后才重新得到字典。
5.8 字典嵌套
字典的值可以是另一个字典,因此可以用来描述复杂的业务对象。
users = {
1001: {
"name": "张三",
"age": 25,
"address": {
"province": "河南",
"city": "安阳"
}
},
1002: {
"name": "李四",
"age": 30,
"address": {
"province": "北京",
"city": "北京"
}
}
}获取嵌套数据:
print(users[1001]["name"]) print(users[1001]["address"]["city"])
如果某个字段可能不存在,可以分步使用 get():
user = users.get(1001, {})
address = user.get("address", {})
city = address.get("city")
print(city)这种方式能够避免部分 KeyError,但如果字段值可能是 None,仍然需要根据业务规则进一步判断。
5.9 字典浅拷贝与深拷贝
这是 Python 容器中一个非常容易出错的知识点。
先看下面的例子:
original = {
"name": "张三",
"scores": [80, 90, 95]
}
copied = original.copy()
copied["name"] = "李四"
copied["scores"].append(100)
print(original)
print(copied)虽然使用了 copy(),但原字典中的 scores 也会发生变化。
原因是:copy() 只复制最外层字典,内部的列表仍然是共享的。
深拷贝
import copy
original = {
"name": "张三",
"scores": [80, 90, 95]
}
copied = copy.deepcopy(original)
copied["scores"].append(100)
print(original["scores"]) # [80, 90, 95]
print(copied["scores"]) # [80, 90, 95, 100]两者的区别:
浅拷贝:复制容器外层,内部对象可能共享。
深拷贝:递归复制符合条件的内部对象,通常可以避免嵌套可变对象相互影响。
深拷贝可能产生额外的时间和内存开销,因此不需要时不要盲目使用。
六、字典的高级应用
前面介绍了字典的基础操作,下面结合实际开发中常见的问题,进一步理解字典的使用价值。
6.1 使用字典统计词频
假设需要统计一段文本中每个单词出现的次数。
text = "python is easy python is powerful"
word_count = {}
for word in text.split():
word_count[word] = word_count.get(word, 0) + 1
print(word_count)核心逻辑是:
word_count[word] = word_count.get(word, 0) + 1
如果单词第一次出现,就从 0 开始计数;如果已经出现过,就在原有数量上加 1。
对于更复杂的统计任务,也可以使用标准库 collections.Counter:
from collections import Counter text = "python is easy python is powerful" word_count = Counter(text.split()) print(word_count) print(word_count.most_common(2))
6.2 使用 defaultdict 简化分组
当需要把多个数据分组到不同的键下面时,可以使用 defaultdict。
from collections import defaultdict
students = [
("张三", "一班"),
("李四", "二班"),
("王五", "一班"),
("赵六", "二班")
]
groups = defaultdict(list)
for name, class_name in students:
groups[class_name].append(name)
print(dict(groups))相比普通字典,defaultdict(list) 会在访问不存在的键时自动创建默认列表。
普通字典也能实现同样的功能:
groups = {}
for name, class_name in students:
groups.setdefault(class_name, []).append(name)两种方式都很实用,选择时可以根据代码的可读性和具体需求决定。
6.3 字典作为缓存
在某些计算成本较高的场景中,可以使用字典保存已经计算过的结果。
cache = {}
def square(n):
if n not in cache:
print("执行计算")
cache[n] = n * n
return cache[n]
print(square(5)) # 执行计算,然后输出 25
print(square(5)) # 直接返回缓存结果 25这个示例展示了缓存的基本思想:相同输入再次出现时,优先使用已保存的结果。
实际项目中,如果需要处理缓存过期、并发访问、容量限制等问题,通常需要使用更完善的缓存方案。
6.4 使用字典处理接口数据
在 FastAPI 等 Web 开发框架中,字典常用于组织响应数据。
from fastapi import FastAPI
app = FastAPI()
@app.get("/user/{user_id}")
def get_user(user_id: int):
return {
"code": 200,
"message": "success",
"data": {
"user_id": user_id,
"name": "张三",
"active": True
}
}当接口返回字典时,FastAPI 通常会将其转换为 JSON 响应。
字典特别适合表示 JSON 中的对象结构,因此在接口开发、配置管理和数据交换中应用非常广泛。不过,如果项目需要严格的字段校验和类型约束,使用 Pydantic 模型往往更清晰。
七、字典的底层原理与性能
理解字典的底层原理,可以帮助我们更合理地使用它。
7.1 字典为什么查询速度快?
Python 字典主要基于哈希表实现。
当执行下面的操作时:
user = {
"name": "张三",
"age": 25
}
print(user["name"])Python 会根据键计算哈希值,再通过哈希表查找对应的键值对。
在通常情况下,字典的查询、插入和删除操作平均时间复杂度为 (O(1))。
但这并不意味着所有操作都一定是常数时间:哈希冲突、扩容等情况可能带来额外开销。
7.2 字典与列表的查询效率
假设需要判断一个用户 ID 是否存在。
使用列表:
user_ids = [1001, 1002, 1003, 1004] print(1003 in user_ids)
列表通常需要逐个检查元素,平均和最坏情况下的时间复杂度与元素数量相关。
使用集合或字典:
user_map = {
1001: "张三",
1002: "李四",
1003: "王五"
}
print(1003 in user_map)对于需要频繁按键查找的场景,字典通常更合适。
| 操作 | 列表 list | 字典 dict |
|---|---|---|
| 按索引访问 | 通常为 (O(1)) | 不适用 |
| 按键查询 | 不适用 | 平均 (O(1)) |
| 判断元素是否存在 | 通常为 (O(n)) | 判断键平均 (O(1)) |
| 按值查找 | 通常为 (O(n)) | 通常为 (O(n)) |
注意:字典中的 value 并没有自动建立索引。若需要频繁按值查找,应考虑额外建立反向索引。
7.3 为什么列表不能直接作为字典的键?
data = {
[1, 2, 3]: "value"
}上面的代码会抛出 TypeError,因为列表是可变对象,不可哈希。
可以改用元组:
data = {
(1, 2, 3): "value"
}但元组能否作为键,取决于其中所有元素是否都可哈希。
例如:
data = {
(1, [2, 3]): "value"
}仍然会报错,因为元组内部包含列表。
八、Python 容器的选择建议
不同容器适合不同的业务场景,实际开发中应该根据数据特征选择合适的类型。
| 使用场景 | 推荐容器 | 原因 |
|---|---|---|
| 保存有序任务列表 | list | 支持索引、追加和删除 |
| 保存固定结构的数据 | tuple | 不可变,适合表达固定记录 |
| 对数据去重 | set | 自动保证元素唯一 |
| 通过 ID 查询用户 | dict | 适合按键快速查找 |
| 统计元素出现次数 | Counter | 提供便捷的计数功能 |
| 按类别收集数据 | defaultdict | 可以自动创建默认容器 |
| 记录计算缓存 | dict | 能够建立输入与结果的映射 |
在实际项目中,这些容器经常配合使用。例如,使用列表保存用户记录,使用字典按用户 ID 建立索引,再使用集合记录已经处理过的 ID。
九、总结
Python 的容器是日常开发的基础能力。列表适合保存有序数据,元组适合表示固定结构,集合适合去重和集合运算,而字典则是处理键值映射的核心工具。
尤其需要掌握字典的以下内容:
创建、增删改查以及
get()的使用。keys()、values()、items()三种遍历方式。字典推导式与数据筛选。
update()、|和**解包等合并方式。嵌套字典、浅拷贝与深拷贝。
Counter、defaultdict和字典缓存等实际应用。哈希表原理以及常见操作的时间复杂度。
熟练掌握这些知识,不仅可以写出更简洁的 Python 代码,也能为后续学习 FastAPI、数据库开发、数据处理和 AI 应用开发打下扎实的基础。
建议: 学习容器时不要只记忆方法名称,更重要的是结合真实业务练习,例如用户信息管理、商品库存统计、接口数据转换和文本词频统计。理解每种容器的适用场景,才能在实际项目中做出更合理的选择。
到此这篇关于Python容器从列表、元组、集合到字典,重点掌握dict的文章就介绍到这了,更多相关Python容器详解内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
