python

关注公众号 jb51net

关闭
首页 > 脚本专栏 > python > Python字典操作指南

Python字典创建、访问、修改、删除及遍历的完整指南

作者:念恒12306

在编程中,我们经常需要建立一种映射关系:比如通过学号找到学生姓名,通过商品编号找到价格,Python 的字典(dict)正是为此而生,因此本文给大家详细介绍了Python字典创建、访问、修改、删除及遍历的完整指南,需要的朋友可以参考下

在编程中,我们经常需要建立一种“映射关系”:比如通过学号找到学生姓名,通过商品编号找到价格。Python 的字典(dict)正是为此而生。它是一种可变无序(Python 3.7+ 保持插入顺序)、键唯一的映射类型,通过哈希表实现 O(1) 的平均查找速度。

1. 字典是什么?

字典是键值对(key-value pair)的集合。每个键对应一个值,键必须是不可变类型(如字符串、数字、元组),值可以是任意类型。

# 一个简单的字典:学生信息
student = {"name": "张三", "age": 20, "major": "计算机"}
print(student["name"])   # 输出:张三

代码解析

核心特性

C/C++ 联动

#include <unordered_map>
#include <string>
std::unordered_map<std::string, int> student = {{"name", 20}, {"age", 20}};
// 访问:student["name"] 或 student.at("name")

2. 创建字典

2.1 使用花括号{}

# 空字典
empty = {}

# 带初始值
person = {"name": "李四", "age": 25}

代码解析

2.2 使用dict()构造函数

# 从关键字参数创建
person = dict(name="王五", age=30)

# 从可迭代对象(如列表的元组对)创建
items = [("name", "赵六"), ("age", 28)]
person = dict(items)   # {'name': '赵六', 'age': 28}

# 空字典
empty = dict()

代码解析

C/C++ 联动

std::unordered_map<std::string, int> person = {{"name", 30}, {"age", 25}};

2.3 使用zip()组合两个序列

keys = ["a", "b", "c"]
values = [1, 2, 3]
d = dict(zip(keys, values))   # {'a': 1, 'b': 2, 'c': 3}

代码解析

2.4 字典推导式(见7 )

3. 访问字典

3.1 通过键访问([])

d = {"apple": 5, "banana": 3}
print(d["apple"])   # 5
# print(d["orange"])  # KeyError: 'orange'

代码解析

C/C++ 联动

std::unordered_map<std::string, int> d;
int val = d["orange"];   // 插入键 "orange" 并值为 0,val = 0

3.2 使用get()方法(安全访问)

print(d.get("orange"))        # None(不报错)
print(d.get("orange", 0))     # 0(指定默认值)

代码解析

C/C++ 联动:C++ 中无直接对应的 get 方法,通常使用 find 并检查迭代器:

auto it = d.find("orange");
int val = (it != d.end()) ? it->second : 0;

3.3 获取所有键、值、键值对

d = {"a": 1, "b": 2}
print(d.keys())     # dict_keys(['a', 'b'])
print(d.values())   # dict_values([1, 2])
print(d.items())    # dict_items([('a', 1), ('b', 2)])

代码解析

C/C++ 联动:C++ 中获取所有键需要手动遍历或使用 range-based for:

for (const auto& pair : d) {
    // pair.first 是键,pair.second 是值
}

3.4 setdefault()—— 获取值,若键不存在则设置默认值

d = {"a": 1}
v = d.setdefault("b", 100)   # 键 "b" 不存在,设置 d["b"]=100,并返回 100
print(d)   # {'a': 1, 'b': 100}
v2 = d.setdefault("a", 99)   # 键存在,返回原值 1,不修改

代码解析

C/C++ 联动:C++ 中可以用 insert 配合 try_emplace 实现类似功能,但不如 Python 简洁。

4. 修改字典

4.1 添加或更新键值对

d = {}
d["name"] = "张三"   # 添加
d["age"] = 25        # 添加
d["age"] = 26        # 更新

代码解析

 C/C++ 联动:C++ 中 unordered_map 的 operator[] 同样可添加或更新,但区别在于:如果键不存在,会插入默认构造的值再赋值。例如 d["age"] = 25 会先检查,若不存在则插入 int()(即0),再赋值为 25。因此 C++ 中不能直接用 [] 判断是否存在。

4.2 update()—— 合并另一个字典或可迭代对象

d1 = {"a": 1, "b": 2}
d2 = {"b": 3, "c": 4}
d1.update(d2)        # d1 变为 {'a': 1, 'b': 3, 'c': 4}
# 也支持关键字参数:d1.update(c=5, d=6)

代码解析

C/C++ 联动:C++ 中合并两个 unordered_map 需要循环插入,没有直接方法。

5. 删除字典元素

5.1 del语句

d = {"a": 1, "b": 2, "c": 3}
del d["b"]           # 删除键为 "b" 的项
# del d["x"]         # KeyError 若键不存在

代码解析

5.2 pop()—— 删除并返回指定键的值

value = d.pop("a")   # 返回 1,d 变为 {'c': 3}
# d.pop("x")         # KeyError
d.pop("x", None)     # 不报错,返回 None

代码解析

C/C++ 联动:C++ 中 unordered_map 的 erase 方法删除键并返回被删除元素的数量(0或1),不返回值。要获取值需先 find

5.3 popitem()—— 删除并返回最后一个键值对(Python 3.7+ 按 LIFO)

d = {"a": 1, "b": 2}
key, value = d.popitem()   # 返回 ('b', 2)(插入顺序的最后一个)

代码解析

5.4 clear()—— 清空字典

d.clear()            # {}

代码解析:删除字典中所有键值对,使字典变为空字典 {}

6. 遍历字典

6.1 遍历键

for key in d:
    print(key)
# 或 for key in d.keys():

代码解析:直接使用 for key in d 是遍历字典最常用的方式,每次迭代获取一个键。也可以用 d.keys() 显式获取键视图。

6.2 遍历值

for value in d.values():
    print(value)

代码解析d.values() 返回值的视图,用于遍历所有值。注意:值可能重复,且无法直接通过值找到对应的键(除非反向查找)。

6.3 同时遍历键和值

for key, value in d.items():
    print(key, value)

代码解析d.items() 返回键值对视图,每个元素是一个 (key, value) 元组。通过拆包可以直接获取键和值。

6.4 带条件或转换的遍历

# 只打印值大于 10 的项
for k, v in d.items():
    if v > 10:
        print(k, v)

代码解析:可以在循环体内加入条件判断,过滤出满足条件的键值对。

7. 字典推导式

与列表推导式类似,用于快速生成字典。

# 平方映射
squares = {x: x**2 for x in range(5)}   # {0:0, 1:1, 2:4, 3:9, 4:16}

代码解析:基本语法 {key_expr: value_expr for variable in iterable}。这里 x 是迭代变量,键是 x,值是 x**2

# 条件过滤:只保留偶数键
even_squares = {x: x**2 for x in range(10) if x % 2 == 0}

代码解析:在推导式末尾加上 if 子句,只对满足条件的 x 生成键值对。

# 交换键和值
original = {"a": 1, "b": 2}
inverted = {v: k for k, v in original.items()}   # {1: 'a', 2: 'b'}

代码解析:遍历原字典的 items(),将键和值互换作为新字典的键值对。注意:如果原字典有重复的值,后面的会覆盖前面的,因为键必须唯一。

8. 嵌套字典

字典的值可以是另一个字典,用于表示层次化数据。

students = {
    "S001": {"name": "Alice", "score": 85},
    "S002": {"name": "Bob", "score": 92}
}
print(students["S001"]["name"])   # Alice

代码解析

安全访问嵌套:逐层使用 get 或使用 try-except

9. 字典的常用方法汇总

方法说明
get(key, default)安全获取值,键不存在时返回默认值(默认 None)。
setdefault(key, default)如果键存在,返回其值;否则设置 d[key]=default 并返回 default。
update([other])用另一个字典或键值对序列更新当前字典。
keys()返回所有键的视图。
values()返回所有值的视图。
items()返回所有 (键, 值) 对的视图。
pop(key, default)删除指定键并返回其值,若不存在返回 default(若未提供则 KeyError)。
popitem()删除并返回最后一个插入的键值对(Python 3.7+)。
clear()清空字典。
copy()浅拷贝。
fromkeys(iterable, value)类方法,从可迭代对象创建字典,所有值初始为 value。

10. 字典的性能与底层原理

10.1 哈希表

Python 字典底层使用哈希表(hash table)。每个键通过哈希函数计算出一个整数索引,用于快速定位存储位置。因此查找、插入、删除的平均时间复杂度为 O(1),但最坏情况(哈希冲突严重)可能退化为 O(n)。Python 通过开放地址法和伪随机探测解决冲突,并自动调整表的大小(rehash)来维持高效。

C/C++ 联动

10.2 键的要求

# 合法键
d = {("a", 1): "tuple"}
# 非法键
# d = {["a", 1]: "list"}   # TypeError: unhashable type: 'list'

代码解析

C/C++ 联动:C++ 中 unordered_map 的键也需要可哈希。内置类型已有标准哈希,自定义类型需要提供 hash 特化和 operator==。例如:

struct MyKey {
    int a;
    std::string b;
    bool operator==(const MyKey& other) const { return a==other.a && b==other.b; }
};
namespace std {
    template<> struct hash<MyKey> {
        size_t operator()(const MyKey& k) const {
            return hash<int>()(k.a) ^ (hash<string>()(k.b) << 1);
        }
    };
}

10.3 内存占用

字典比列表占用更多内存(约 2~3 倍),因为哈希表需要预留额外空间。

11. 扩展:collections 模块中的字典变种

11.1 defaultdict—— 带默认工厂的字典

当访问不存在的键时,自动创建默认值,避免 KeyError

from collections import defaultdict

# 默认值为整数 0
dd = defaultdict(int)
dd["a"] += 1        # 不需要先检查 "a" 是否存在
print(dd)           # {'a': 1}

代码解析

# 默认值为空列表
dd2 = defaultdict(list)
dd2["group"].append(10)   # 自动创建列表
print(dd2)                # {'group': [10]}

代码解析list 工厂函数会在键缺失时创建一个空列表,然后可以安全地 append

常见工厂intlistsetstr, 或自定义函数。

C/C++ 联动:C++ 中 unordered_map 的 operator[] 在键不存在时会插入默认值(值类型的默认构造)。例如 std::unordered_map<std::string, int> m; m["a"] += 1; 会先插入 int()(0),再自增。这与 defaultdict(int) 行为类似,但 Python 的 defaultdict 可以灵活指定任何工厂函数(如 list),而 C++ 的默认构造只适用于值类型。

11.2 Counter—— 计数器

用于统计可哈希元素出现的次数。

from collections import Counter

colors = ["red", "blue", "red", "green", "blue", "red"]
cnt = Counter(colors)
print(cnt)          # Counter({'red': 3, 'blue': 2, 'green': 1})
print(cnt["red"])   # 3
print(cnt.most_common(2))  # [('red', 3), ('blue', 2)]

代码解析

C/C++ 联动:C++ 中没有 Counter 的直接对应,但可以用 unordered_map 实现计数,再借助 vector 排序获取最值。Python 的 Counter 更高级,内置了 most_common 等便捷方法。

11.3 OrderedDict—— 保持插入顺序(Python 3.7+ 中普通 dict 已有序)

在 Python 3.6 之前,字典无序,OrderedDict 用于保持插入顺序。现在普通 dict 也保持顺序,但 OrderedDict 还额外提供了 move_to_end() 等方法。

from collections import OrderedDict
od = OrderedDict()
od["a"] = 1
od["b"] = 2
od.move_to_end("a")   # 将 "a" 移到末尾

代码解析move_to_end(key, last=True) 将指定键移动到末尾(如果 last=False 则移动到开头)。

 C/C++ 联动:C++ 中保持插入顺序没有标准容器直接支持。可以使用 std::vector 配合 unordered_map 来记录顺序,或使用 boost::multi_index。Python 3.7+ 普通 dict 已有序,这是比 C++ 方便的特性。

11.4 ChainMap—— 将多个字典合并成一个视图

用于查找时按顺序搜索多个字典。

from collections import ChainMap
d1 = {"a": 1, "b": 2}
d2 = {"b": 3, "c": 4}
chain = ChainMap(d1, d2)
print(chain["b"])   # 从 d1 找到 2(取第一个)

代码解析

C/C++ 联动:C++ 无直接对应,但可用多个 map 和自定义搜索逻辑实现。

12. 字典与列表、元组的对比

特性字典列表元组
容器类型映射(键值对)序列序列
有序性Python 3.7+ 插入有序有序有序
可变性可变可变不可变
索引方式键(不可变类型)整数索引整数索引
查找速度平均 O(1)O(n)O(n)
内存占用较大中等略小于列表
典型用途关联数据、快速查找有序序列不可变序列

13. 字典的应用实战

13.1 统计字符串中字符出现次数

text = "hello world"
freq = {}
for ch in text:
    if ch != " ":
        freq[ch] = freq.get(ch, 0) + 1
print(freq)

代码解析

13.2 使用字典实现简单缓存(记忆化)

def fibonacci(n, cache={}):
    if n in cache:
        return cache[n]
    if n <= 1:
        return n
    cache[n] = fibonacci(n-1) + fibonacci(n-2)
    return cache[n]

代码解析

13.3 根据值排序字典

d = {"apple": 3, "banana": 1, "cherry": 2}
# 按值升序排序,得到键的列表
sorted_keys = sorted(d, key=d.get)           # ['banana', 'cherry', 'apple']
# 按值降序排序,得到键值对列表
sorted_items = sorted(d.items(), key=lambda x: x[1], reverse=True)

代码解析

13.4 合并两个字典(Python 3.9+ 使用|)

d1 = {"a": 1, "b": 2}
d2 = {"b": 3, "c": 4}
merged = d1 | d2        # {'a':1, 'b':3, 'c':4}
d1 |= d2                # 原地更新(Python 3.9+)

代码解析

C/C++ 联动:C++ 中合并两个 unordered_map 无运算符重载,需手动循环插入。

14. 常见陷阱与注意事项

陷阱说明解决方案
使用可变对象作为键列表、字典等不可哈希,会报错改用元组或字符串
在遍历字典时修改字典会导致 RuntimeError: dictionary changed size during iteration遍历 list(d.keys()) 或 d.copy().items()
混淆 get 和 setdefaultsetdefault 会修改字典,get 不会按需选择
认为字典总是无序(旧代码)Python 3.7+ 插入顺序被保证,但依赖此特性的代码需要最低版本使用 OrderedDict 若需严格兼容低版本
在 defaultdict 中传递可变对象工厂函数使用 list 而非 list(),传递可调用对象defaultdict(list) 正确,defaultdict(list()) 错误
拷贝字典时使用 = 而非 copy二者指向同一对象,修改会互相影响浅拷贝用 d.copy(),深拷贝用 copy.deepcopy

C/C++ 联动

以上就是Python字典创建、访问、修改、删除及遍历的完整指南的详细内容,更多关于Python字典操作指南的资料请关注脚本之家其它相关文章!

您可能感兴趣的文章:
阅读全文