Python 字典(Dictionary)详解
在 Python 中,字典(Dictionary)是一种键值对(key-value) 结构的可变容器,类似于 Java 中的 Map 或 JavaScript 中的对象。它通过键(key)快速查找对应的值(value),是处理关联数据的核心数据结构。本文将详细介绍字典的创建、操作及常用方法。
字典的基本定义
字典使用大括号 {} 定义,键值对之间用逗号分隔,键与值用冒号 : 连接。
# 基本字典(键为字符串,值为整数)
student = {'name': 'Alice', 'age': 20, 'major': 'Computer Science'}
# 键可以是任意不可变类型(如整数、字符串、元组)
mixed_dict = {
1: 'one', # 整数作为键
('a', 'b'): 123, # 元组作为键(元组不可变)
'list': [1, 2, 3] # 值可以是任意类型(包括列表、字典等)
}
# 空字典
empty_dict = {}
# 用 dict() 函数创建字典
another_dict = dict(name='Bob', age=21) # 等价于 {'name': 'Bob', 'age': 21}
注意:
- 键必须是不可变类型(如字符串、整数、元组),列表等可变类型不能作为键。
- 键是唯一的,若重复定义,后面的键值对会覆盖前面的。
字典的核心操作
访问值(通过键)
通过 字典名[键] 访问对应的值,若键不存在则报错。
student = {'name': 'Alice', 'age': 20}
print(student['name']) # 输出:Alice(访问 name 对应的值)
print(student['age']) # 输出:20(访问 age 对应的值)
# 使用 get() 方法访问(键不存在时返回默认值,避免报错) 可以通过 'major' in student 来判断该键是否存在
print(student.get('major', 'Unknown')) # 输出:Unknown(键 'major' 不存在,返回默认值)
添加 / 修改键值对
student = {'name': 'Alice', 'age': 20}
# 添加新键值对
student['major'] = 'Math'
print(student) # 输出:{'name': 'Alice', 'age': 20, 'major': 'Math'}
# 修改已有键的值
student['age'] = 21
print(student) # 输出:{'name': 'Alice', 'age': 21, 'major': 'Math'}
删除键值对
student = {'name': 'Alice', 'age': 21, 'major': 'Math'}
# 删除指定键
del student['major']
print(student) # 输出:{'name': 'Alice', 'age': 21}
# 删除并返回值
age = student.pop('age')
print(age) # 输出:21
print(student) # 输出:{'name': 'Alice'}
# 清空字典
student.clear()
print(student) # 输出:{}
字典的遍历
字典提供多种方式遍历键、值或键值对:
遍历所有键(keys())
fruit_prices = {'apple': 5, 'banana': 3, 'orange': 4}
# 直接遍历字典(默认遍历键)
for fruit in fruit_prices:
print(fruit) # 输出:apple、banana、orange
# 使用 keys() 方法(更清晰)
for fruit in fruit_prices.keys():
print(fruit) # 输出同上
遍历所有值(values())
fruit_prices = {'apple': 5, 'banana': 3, 'orange': 4}
for price in fruit_prices.values():
print(price) # 输出:5、3、4
遍历键值对(items())
fruit_prices = {'apple': 5, 'banana': 3, 'orange': 4}
# items() 返回包含 (键, 值) 元组的可迭代对象
for fruit, price in fruit_prices.items():
print(f"水果:{fruit},价格:{price}元")
# 输出:
# 水果:apple,价格:5元
# 水果:banana,价格:3元
# 水果:orange,价格:4元
常用方法速查表
| | | |
|---|
d[key] | | | value = d['key'] |
d.get(key[, default]) | | | d.get('key', 0) |
d[key] = value | | | d['new'] = 100 |
d.update(other) | | | d.update({'a':1, 'b':2}) |
del d[key] | | | del d['key'] |
d.pop(key[, default]) | | | value = d.pop('key', None) |
d.popitem() | | | k, v = d.popitem() |
d.clear() | | | d.clear() |
d.keys() | | | for k in d.keys(): |
d.values() | | | for v in d.values(): |
d.items() | | | for k, v in d.items(): |
d.copy() | | | new_d = d.copy() |
d.setdefault(key[, default]) | | | d.setdefault('count', 0) |
len(d) | | | size = len(d) |
key in d | | | if 'key' in d: |
| | | |
| | | |
示例:update() 和 copy()
# update():合并字典(覆盖重复键)
dict1 = {'a': 1, 'b': 2}
dict2 = {'b': 3, 'c': 4}
dict1.update(dict2)
print(dict1) # 输出:{'a': 1, 'b': 3, 'c': 4}(b 的值被覆盖)
# copy():复制字典
dict3 = dict1.copy()
dict3['a'] = 100
print(dict1) # 输出:{'a': 1, 'b': 3, 'c': 4}(原字典不变)
print(dict3) # 输出:{'a': 100, 'b': 3, 'c': 4}(副本被修改)
进阶技巧与实战
实战1:单词计数器
defword_count(text):
"""统计文本中每个单词出现的次数"""
word_counts = {}
# 方法1:传统方式
for word in text.lower().split():
if word in word_counts:
word_counts[word] += 1
else:
word_counts[word] = 1
# 方法2:使用 get()(更简洁)
# for word in text.lower().split():
# word_counts[word] = word_counts.get(word, 0) + 1
# 方法3:使用 defaultdict(最优雅)
# from collections import defaultdict
# word_counts = defaultdict(int)
# for word in text.lower().split():
# word_counts[word] += 1
return word_counts
text = "hello world hello python hello world"
print(word_count(text))
# {'hello': 3, 'world': 2, 'python': 1}
实战2:分组与聚合
# 场景:按城市分组用户
users = [
('Alice', 'NYC', 25),
('Bob', 'LA', 30),
('Charlie', 'NYC', 35),
('Diana', 'LA', 28),
]
# 分组:城市 → 用户列表
city_users = {}
for name, city, age in users:
city_users.setdefault(city, []).append({'name': name, 'age': age})
print(city_users)
# {
# 'NYC': [{'name': 'Alice', 'age': 25}, {'name': 'Charlie', 'age': 35}],
# 'LA': [{'name': 'Bob', 'age': 30}, {'name': 'Diana', 'age': 28}]
# }
实战3:字典作为缓存(Memoization)
# 斐波那契数列缓存
fib_cache = {}
deffibonacci(n):
"""带缓存的斐波那契函数(性能提升巨大)"""
if n in fib_cache:
return fib_cache[n]
if n <= 1:
result = n
else:
result = fibonacci(n-1) + fibonacci(n-2)
fib_cache[n] = result
return result
# 对比性能
import time
start = time.time()
print(fibonacci(40)) # 102334155
print(f"耗时:{time.time() - start:.4f}秒") # 约 0.001 秒(无缓存需 30+ 秒)
实战4:使用字典模拟 switch-case
defswitch_example(operation, x, y):
"""使用字典替代多个 if-elif"""
operations = {
'add': lambda: x + y,
'subtract': lambda: x - y,
'multiply': lambda: x * y,
'divide': lambda: x / y if y != 0else float('inf'),
}
return operations.get(operation, lambda: "Invalid operation")()
print(switch_example('add', 10, 5)) # 15
print(switch_example('multiply', 10, 5)) # 50
print(switch_example('power', 10, 5)) # Invalid operation
常见陷阱与性能优化
🚨 陷阱1:在遍历时修改字典
# ❌ 错误:RuntimeError: dictionary changed size during iteration
d = {'a': 1, 'b': 2, 'c': 3}
# for key in d:
# if key == 'b':
# del d[key] # 报错!
# ✅ 正确:遍历副本
for key in list(d.keys()): # 转换为列表
if key == 'b':
del d[key]
print(d) # {'a': 1, 'c': 3}
🚨 陷阱2:浅拷贝陷阱
# ❌ 问题:浅拷贝复制的是引用
original = {'list': [1, 2, 3]}
shallow_copy = original.copy()
shallow_copy['list'].append(4)
print(original['list']) # [1, 2, 3, 4] ← 原字典也被修改!
# ✅ 深拷贝
import copy
original = {'list': [1, 2, 3]}
deep_copy = copy.deepcopy(original)
deep_copy['list'].append(4)
print(original['list']) # [1, 2, 3] ← 不受影响
🚨 陷阱3:可变对象作为默认值
# ❌ 错误:所有调用共享同一个字典
defadd_user(name, user_dict={}):
user_dict[name] = len(user_dict)
return user_dict
print(add_user('Alice')) # {'Alice': 0}
print(add_user('Bob')) # {'Alice': 0, 'Bob': 1} ← 意外共享!
# ✅ 正确:使用 None 作为哨兵
defadd_user(name, user_dict=None):
if user_dict isNone:
user_dict = {}
user_dict[name] = len(user_dict)
return user_dict
print(add_user('Alice')) # {'Alice': 0}
print(add_user('Bob')) # {'Bob': 0}
性能优化建议
# 1. 使用 in 代替 has_key()(已废弃)
if'key'in d: # ✅ 快速
pass
# 2. 批量操作使用 update 而非循环
d = {}
new_items = {'a': 1, 'b': 2, 'c': 3}
d.update(new_items) # ✅ O(k)
# 等价于:
# for k, v in new_items.items(): # ❌ 较慢
# d[k] = v
# 3. 字典推导式比循环快 30%+
squares = {x: x**2for x in range(1000)} # ✅ 快速
# vs
squares = {} # ❌ 较慢
# for x in range(1000):
# squares[x] = x**2
# 4. 预设容量减少扩容(Python 3.7+)
d = {}
d.__sizeof__() # 初始容量 8
d = {'a': 1, 'b': 2, 'c': 3, 'd': 4, 'e': 5} # 会触发扩容
总结与选型指南
何时使用字典?
| | |
|---|
| | |
| | |
| | |
| | config = {'host': 'localhost'} |
| | |
| | |
| | |