Python3 字典

在 Python 3 中,字典(Dictionary) 是最强大、最常用的数据结构之一。它通过键值对(Key-Value pairs) 来存储数据,底层基于哈希表(Hash Table) 实现,这使得它的查找、插入和删除操作平均时间复杂度都达到了惊人的 O(1)

💡 重要特性:从 Python 3.7 开始,字典严格保证保持元素的插入顺序。这是现代 Python 的一个重大改进。

下面我将从基础操作高级技巧现代语法常见陷阱,为你全面解析 Python 3 字典。


一、 创建与初始化字典

有多种方式可以创建字典,适用于不同的场景。

纯文本
# 1. 字面量创建 (最常用、最直观)
user = {"name": "Alice", "age": 25, "city": "Beijing"}

# 2. 使用 dict() 构造函数
# 方式 A: 传入关键字参数 (键必须是合法的标识符,即字符串且不能以数字开头)
config = dict(host="localhost", port=8080, debug=True)

# 方式 B: 传入包含键值对的元组列表
items = dict([("name", "Bob"), ("age", 30)])

# 3. 使用 fromkeys() 快速创建具有相同默认值的字典
keys = ["a", "b", "c"]
default_dict = dict.fromkeys(keys, 0) 
print(default_dict)  # 输出: {'a': 0, 'b': 0, 'c': 0}

二、 核心操作:增、删、改、查

纯文本
my_dict = {"apple": 3, "banana": 5}

# 1. 查 (访问)
print(my_dict["apple"])  # 输出: 3
# print(my_dict["orange"]) # ❌ 会抛出 KeyError: 'orange'

# ✅ 安全访问:使用 .get(),找不到时返回 None 或指定的默认值
print(my_dict.get("orange", 0))  # 输出: 0 (强烈推荐这种做法)

# 2. 改 (修改)
my_dict["apple"] = 10  # 键存在,则更新值

# 3. 增 (添加)
my_dict["orange"] = 8  # 键不存在,则添加新键值对

# 4. 删 (删除)
del my_dict["banana"]           # 删除指定键,不存在会报 KeyError
value = my_dict.pop("apple")    # 删除并返回该键的值,可带默认值防止报错
last_item = my_dict.popitem()   # 删除并返回**最后插入**的键值对 (Python 3.7+)
my_dict.clear()                 # 清空字典

三、 遍历字典的 3 种标准姿势

在循环中处理字典时,Python 提供了极其优雅的方法。

纯文本
scores = {"Alice": 95, "Bob": 88, "Charlie": 92}

# 1. 遍历键 (默认行为,等同于 scores.keys())
for key in scores:
    print(key)

# 2. 遍历值
for value in scores.values():
    print(value)

# 3. 遍历键值对 (最常用,利用元组解包)
for name, score in scores.items():
    print(f"{name} 的分数是 {score}")

四、 高级技巧与现代语法 (Python 3.5+)

1. 字典合并与更新

  • .update():就地更新字典(修改原字典)。
    python dict1 = {"a": 1, "b": 2} dict2 = {"b": 3, "c": 4} dict1.update(dict2) print(dict1) # 输出: {'a': 1, 'b': 3, 'c': 4} (b 的值被覆盖)
  • ||= 运算符 (Python 3.9+ 新增):更优雅的合并方式。 dict1 = {"a": 1, "b": 2} dict2 = {"b": 3, "c": 4} # | 创建新字典,不修改原字典 merged = dict1 | dict2 # {'a': 1, 'b': 3, 'c': 4} # |= 就地更新 dict1 dict1 |= dict2

2. 字典解包 (**)

在函数传参或合并字典时非常有用。

纯文本
defaults = {"host": "localhost", "port": 80}
overrides = {"port": 8080, "debug": True}

# 合并字典 (Python 3.5+)
config = {**defaults, **overrides}
print(config)  # 输出: {'host': 'localhost', 'port': 8080, 'debug': True}

3. setdefault():优雅的“如果不存在则设置”

当你需要初始化字典中的列表或集合时,这个方法是神器。

纯文本
# 场景:按类别分组数据
data = [("fruit", "apple"), ("fruit", "banana"), ("color", "red")]
groups = {}

for category, item in data:
    # 如果 category 不存在,先设为空列表 [],然后 append
    groups.setdefault(category, []).append(item)

print(groups)  
# 输出: {'fruit': ['apple', 'banana'], 'color': ['red']}

(注:对于复杂的分组场景,前文提到的 collections.defaultdict 是更好的选择)

4. 字典推导式 (Dictionary Comprehension)

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

纯文本
numbers = [1, 2, 3, 4]

# 生成 {数字: 数字的平方} 的字典
squares_dict = {x: x**2 for x in numbers if x % 2 == 0}
print(squares_dict)  # 输出: {2: 4, 4: 16}

# 翻转字典的键和值 (前提是值是可哈希的且唯一)
original = {"a": 1, "b": 2}
flipped = {v: k for k, v in original.items()}
print(flipped)  # 输出: {1: 'a', 2: 'b'}

五、 ⚠️ 常见陷阱与最佳实践

陷阱 1:键必须是“可哈希的” (Hashable)

字典的键必须是不可变类型(如字符串、数字、元组)。不能使用列表、字典或集合作为键。

纯文本
# ❌ TypeError: unhashable type: 'list'
bad_dict = {[1, 2]: "value"}

# ✅ 正确做法:使用元组作为键
good_dict = {(1, 2): "value"}

(值可以是任何类型,包括列表或字典)

陷阱 2:在遍历字典时修改它的大小

for 循环遍历字典时,如果添加或删除键,会导致 RuntimeError: dictionary changed size during iteration

纯文本
my_dict = {"a": 1, "b": 2, "c": 3}

# ❌ 错误:遍历时删除
# for k in my_dict:
#     if k == "b":
#         del my_dict[k]

# ✅ 正确做法 1:遍历字典键的副本 (list)
for k in list(my_dict.keys()):
    if k == "b":
        del my_dict[k]

# ✅ 正确做法 2:使用字典推导式生成新字典
my_dict = {k: v for k, v in my_dict.items() if k != "b"}

陷阱 3:误以为字典是“按字母顺序”排序的

Python 3.7+ 保证的是插入顺序,而不是按键的字母或数字大小排序。如果需要排序,必须显式使用 sorted()

纯文本
d = {"z": 1, "a": 2, "m": 3}
# 按键排序
sorted_by_key = dict(sorted(d.items())) 
print(sorted_by_key)  # 输出: {'a': 2, 'm': 3, 'z': 1}

六、 总结:何时使用字典?

你的需求推荐数据结构
需要通过名称/标识符快速查找对应的数据dict (例如:通过用户 ID 查用户信息)
需要记录配置项、参数或具有明确属性的实体dict (或 Python 3.7+ 的 @dataclass)
需要统计元素出现次数collections.Counter (字典的子类)
只需要存储唯一值,不需要关联数据set (集合)

字典是 Python 的灵魂数据结构。掌握了 .get() 防错、.items() 遍历、推导式以及 Python 3.9 的 | 合并运算符,你的 Python 代码就会显得非常专业和现代。

你目前是否有处理复杂 JSON 数据、或者需要嵌套字典的具体场景?我可以为你演示如何优雅地解析和操作它们!