字典
Python 字典:你每天都会用到的”通讯录”
写 Python 代码,字典(Dictionary)是我用得最多的数据结构,没有之一。
它就是一个通讯录:你记一个人的名字(键),就能找到他的电话号码(值)。存什么都能快速找到,这就是字典的价值。
字典长什么样?怎么建?
字典用大括号 {},里面是”键:值”的配对,逗号隔开。
# 基本字典(键为字符串,值为整数)
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}
两个规则记住就行:
- 键必须是不可变的。字符串、数字、元组都可以,列表不行。因为列表能变,Python 没法保证它”始终能代表同一个东西”。
- 键不能重复。你如果写了两次同一个键,后面的会覆盖前面的。
增删改查,字典的”四件套”
查:用 [] 或者 get()
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' 不存在,返回默认值)
[] 和 get() 的区别:[] 找不到就报错,程序崩溃;get() 找不到返回默认值,程序还能继续跑。不确定键存不存在的时候,用 get() 更安全。
改/增:直接赋值
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'}
Python 不管你是改还是增,反正 字典[键] = 值 这一句就把键值对放进去了。存在就更新,不存在就新增。
删:del、pop、clear
del 字典名[键]:删除指定键值对。字典名.pop(键):删除并返回指定键的值。字典名.clear():清空字典所有键值对。
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) # 输出:{}
pop 比 del 多一个功能——它把删掉的值返回给你,有时候有用。
遍历字典:取出里面的数据
遍历键
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) # 输出同上
遍历值
fruit_prices = {'apple': 5, 'banana': 3, 'orange': 4}
for price in fruit_prices.values():
print(price) # 输出:5、3、4
遍历键值对(最常用)
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元
几个实战场景,看看字典怎么用
场景1:统计词频
这是字典最经典的应用,没有之一。
text = "hello world hello python hello world"
word_counts = {}
for word in text.lower().split():
word_counts[word] = word_counts.get(word, 0) + 1
# word_counts = {'hello': 3, 'world': 2, 'python': 1}
get(word, 0) 的意思:如果 word 已经在字典里,返回它的值;如果不在,返回 0。然后加 1 赋值回去。一行搞定统计,比用 if-else 简洁多了。
场景2:按类别分组
users = [
('Alice', 'NYC', 25),
('Bob', 'LA', 30),
('Charlie', 'NYC', 35),
]
city_users = {}
for name, city, age in users:
if city not in city_users:
city_users[city] = []
city_users[city].append({'name': name, 'age': age})
# city_users = {
# 'NYC': [{'name': 'Alice', 'age': 25}, {'name': 'Charlie', 'age': 35}],
# 'LA': [{'name': 'Bob', 'age': 30}]
# }
setdefault 可以简化这段代码:
city_users.setdefault(city, []).append({'name': name, 'age': age})
setdefault 的意思是:如果 city 存在,返回它的值;如果不存在,用第二个参数创建默认值并返回。一行代替 if-else 判断。
场景3:用字典替代多个 if-elif
写代码的时候经常遇到一堆 if-elif,看着烦。可以用字典把条件和操作映射起来:
def add(x, y): return x + y
def sub(x, y): return x - y
def mul(x, y): return x * y
operations = {
'add': add,
'subtract': sub,
'multiply': mul,
}
result = operations.get('add', lambda x,y: None)(10, 5) # 15
这个技巧在处理命令分发、路由选择的时候很好用,代码比一堆 if-elif 干净多了。
场景4:缓存计算结果(性能优化)
计算斐波那契数列的时候,不用缓存会重复算很多次。用字典把算过的结果记下来:
cache = {}
def fib(n):
if n in cache:
return cache[n]
if n <= 1:
result = n
else:
result = fib(n-1) + fib(n-2)
cache[n] = result
return result
没缓存的时候算 fib(40) 可能要 30 秒,有缓存 0.001 秒。差别巨大。
几个容易踩的坑
坑1:遍历的时候删东西
d = {'a': 1, 'b': 2, 'c': 3}
for key in d:
if key == 'b':
del d[key] # RuntimeError! 遍历过程中不能修改字典大小
正确做法:遍历字典的副本(转换成列表再遍历):
for key in list(d.keys()):
if key == 'b':
del d[key]
坑2:浅拷贝只复制了外层
original = {'list': [1, 2, 3]}
copy = original.copy()
copy['list'].append(4)
print(original['list']) # [1, 2, 3, 4] 原字典也被改了!
dict.copy() 是浅拷贝,里面的列表还是同一个引用。想完全独立用 copy.deepcopy()。
坑3:可变对象当默认参数
def add_user(name, user_dict={}):
user_dict[name] = len(user_dict)
return user_dict
add_user('Alice') # {'Alice': 0}
add_user('Bob') # {'Alice': 0, 'Bob': 1} 意外共享!
默认参数在函数定义的时候就创建了,每次调用用的是同一个字典对象。正确做法是用 None 占位:
def add_user(name, user_dict=None):
if user_dict is None:
user_dict = {}
user_dict[name] = len(user_dict)
return user_dict