一、默认字典概述
在Python的collections模块中,有一种叫做defaultdict
的数据结构,它是dict
类的一个子类,它能够自动为字典中不存在的键提供默认值。
from collections import defaultdict
# 设置列表为默认值
d = defaultdict(list)
# 字典中没有key为"name"的键,则插入键"name",值为[],即一个空列表
# 并将返回值作为这个列表的引用
d["name"].append("John")
在默认字典中,如果访问字典中不存在的键,则默认会自动创建这个键并且对应的值是在创建defaultdict
时所指定的默认值,最常见的情况就是使用列表为默认值。
二、默认字典的应用
默认字典的应用非常广泛,在以下几个方面,我们可以看到默认字典的强大和方便
1. 计数器Counter
Counter
是collections
模块中的一个计数器,它使用默认字典作为容器,用来计数相同元素出现的次数。
from collections import Counter
# 使用Counter统计列表中各元素出现的次数
L = [1, 2, 1, 3, 2, 1, 2, 4, 5, 1]
c = Counter(L)
print(c) # Counter({1: 4, 2: 3, 3: 1, 4: 1, 5: 1})
使用Counter
的过程,实际上是为每个元素初始化一个默认值,并每次遍历到这个元素是增加计数器。
2. 节省代码行数
使用默认字典可以省去对键是否存在的判断,能大大减少代码行数。比如以下代码:
# 对于每个键,统计它出现的次数,没有出现过则将次数初始化为0
for key in keys:
if key not in d:
d[key] = 0
d[key] += 1
这样的代码可以使用下面的代码来替代:
for key in keys:
d[key] += 1
3. 容器嵌套
在容器嵌套的情况下,使用默认字典可以避免键映射到不存在的值的情况,从而使代码更为紧凑。
# 学生成绩均分统计(d为默认字典,可以方便地追加学生成绩)
d = defaultdict(list)
for name, score in scores:
d[name].append(score)
# 输出每位学生平均分
for name, scores in d.items():
avg_score = sum(scores) / len(scores)
print(f"{name}: {avg_score}")
三、默认字典的用法
虽然默认字典非常便利实用,但是需要注意以下几个问题:
1. 默认值需要可迭代
当我们使用默认字典来创建一个默认空列表的时候,在将这个列表元素加入到默认字典中时,需要的是一个可迭代的对象。
from collections import defaultdict
d = defaultdict(list)
d["name"].append("John") # 正确
d["name"].append("Mike") # 正确
d["name"] = "John" # 错误,字符串不可迭代
2. 默认值的函数要注意副作用
在使用默认值函数时,需要注意函数是否有副作用,建议使用lambda表达式。
# 正确方式:不具有副作用的lambda表达式
d = defaultdict(lambda: [])
# 错误方式:具有副作用的函数
def foo():
print("hello")
return []
d = defaultdict(foo)
d[1] # 输出"hello",并返回一个空列表
d[2] # 输出"hello",并返回一个空列表
3. 默认值函数的应用
我们可以任意定制默认值函数,比如追踪创建了哪些键:
def key_tracker():
c = []
def tracker():
c.append(len(c))
return []
return tracker
tracker = key_tracker()
d = defaultdict(tracker)
_ = d["name1"]
_ = d["name2"]
_ = d["name3"]
print(tracker()) # [0, 1, 2]
四、总结
Python中的默认字典可谓是一个功能强大且便捷实用的数据结构,它大大了简化了容器中键的初始化和增加操作。在实际的Python开发中,我们可以充分发挥其威力,优化代码,简化程序逻辑。