defaultdict是dict的子类,访问不存在的键时自动创建默认值,避免KeyError。它通过指定工厂函数(如int、list、set或lambda)生成默认值,常用于计数、分组和构建复杂数据结构。相比普通dict的get()或if/else,defaultdict代码更简洁,尤其适合累加和追加操作。工厂函数必须无参数且每次调用生成新对象,确保可变类型独立。高级用法包括嵌套defaultdict实现多级分组,但需注意意外添加键、类型不统一及序列化问题,使用时应权衡场景以避免副作用。

defaultdict
dict
KeyError
在使用
defaultdict
collections
from collections import defaultdict
# 1. 计数场景:使用 int 作为工厂函数,默认值是 0
# 比如,我想统计一个列表中每个元素的出现次数
data = ['apple', 'banana', 'apple', 'orange', 'banana', 'apple']
counts = defaultdict(int)
for item in data:
counts[item] += 1
print(f"计数结果: {counts}")
# 输出: defaultdict(<class 'int'>, {'apple': 3, 'banana': 2, 'orange': 1})
# 2. 分组场景:使用 list 作为工厂函数,默认值是空列表
# 比如,我想把一系列数字按奇偶分组
numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9]
grouped_numbers = defaultdict(list)
for num in numbers:
if num % 2 == 0:
grouped_numbers['even'].append(num)
else:
grouped_numbers['odd'].append(num)
print(f"分组结果: {grouped_numbers}")
# 输出: defaultdict(<class 'list'>, {'odd': [1, 3, 5, 7, 9], 'even': [2, 4, 6, 8]})
# 3. 构建图结构:使用 set 作为工厂函数,默认值是空集合
# 比如,表示一个无向图的邻接列表
graph = defaultdict(set)
edges = [('A', 'B'), ('A', 'C'), ('B', 'D'), ('C', 'D'), ('D', 'A')]
for u, v in edges:
graph[u].add(v)
graph[v].add(u) # 无向图,所以两边都要加
print(f"图结构: {graph}")
# 输出: defaultdict(<class 'set'>, {'A': {'C', 'B', 'D'}, 'B': {'A', 'D'}, 'C': {'A', 'D'}, 'D': {'C', 'B', 'A'}})
# 4. 使用 lambda 表达式作为工厂函数,提供更复杂的默认值
# 比如,每个新键的默认值是一个包含 'default' 字符串的列表
complex_defaults = defaultdict(lambda: ['default'])
complex_defaults['key1'].append('value1')
print(f"复杂默认值: {complex_defaults}")
# 输出: defaultdict(<function <lambda> at 0x...>, {'key1': ['default', 'value1']})你看,它的用法其实非常直观。核心就是你告诉它,当键不存在时,给我一个什么样的新东西。
defaultdict
dict
get()
if/else
说实话,我个人觉得
defaultdict
if key not in my_dict: my_dict[key] = initial_value
my_dict.get(key, initial_value)
get()
append
+=
if/else
立即学习“Python免费学习笔记(深入)”;
举个例子,统计单词频率:
使用普通 dict
words = ['apple', 'banana', 'apple', 'orange']
word_counts = {}
for word in words:
if word in word_counts:
word_counts[word] += 1
else:
word_counts[word] = 1
# 或者用 get()
# word_counts[word] = word_counts.get(word, 0) + 1
print(f"普通dict计数: {word_counts}")使用 defaultdict
from collections import defaultdict
words = ['apple', 'banana', 'apple', 'orange']
word_counts_default = defaultdict(int)
for word in words:
word_counts_default[word] += 1
print(f"defaultdict计数: {word_counts_default}")很明显,
defaultdict
+= 1
defaultdict
defaultdict
defaultdict
内置类型构造函数:
int
0
list
[]
set
set()
str
''
float
0.0
dict
{}自定义函数或 lambda
lambda
def create_default_value():
return {'status': 'new', 'data': []}
my_complex_default = defaultdict(create_default_value)
my_complex_default['task1']['data'].append('item1')
print(f"自定义函数默认值: {my_complex_default}")
my_lambda_default = defaultdict(lambda: '未知')
print(f"lambda默认值: {my_lambda_default['non_existent_key']}")需要注意的地方:
defaultdict
defaultdict(dict.fromkeys)
list
set
dict
my_dict['key1']
my_dict['key2']
None
None
callable(None)
False
defaultdict(None)
TypeError
defaultdict
理解这些,能让你更灵活、更安全地使用
defaultdict
defaultdict
在实际项目里,
defaultdict
高级用法:
嵌套 defaultdict
from collections import defaultdict
data_points = [
{'year': 2023, 'month': 1, 'value': 10},
{'year': 2023, 'month': 2, 'value': 20},
{'year': 2024, 'month': 1, 'value': 15},
{'year': 2023, 'month': 1, 'value': 5},
]
# lambda: defaultdict(list) 意思是:如果第一层键不存在,默认值是一个新的 defaultdict,这个新的 defaultdict 的默认值是 list
yearly_monthly_data = defaultdict(lambda: defaultdict(list))
for item in data_points:
year = item['year']
month = item['month']
yearly_monthly_data[year][month].append(item['value'])
print(f"多级分组数据: {yearly_monthly_data}")
# 输出: defaultdict(<function <lambda> at 0x...>, {2023: defaultdict(<class 'list'>, {1: [10, 5], 2: [20]}), 2024: defaultdict(<class 'list'>, {1: [15]})})这种结构在处理日志分析、用户行为统计等场景下非常高效。
用作轻量级缓存或延迟计算: 如果你的默认值计算成本较高,并且希望只在需要时才计算,
defaultdict
import time
def expensive_computation(key):
print(f"正在为键 '{key}' 执行耗时计算...")
time.sleep(1) # 模拟耗时操作
return f"计算结果 for {key}"
# 注意这里不能直接传 expensive_computation,因为它需要一个 key 参数
# 所以我们用 lambda 包裹一下,让它变成无参数调用
cached_results = defaultdict(lambda: expensive_computation(list(cached_results.keys())[-1] if cached_results else "default_key"))
# 上面这个 lambda 表达式有点复杂,因为它试图获取当前 defaultdict 中最后一个键来传递给 expensive_computation。
# 更常见且安全的方式是,如果 expensive_computation 真的需要 key,那 defaultdict 就不是最直接的方案,
# 或者让 factory 返回一个能“记住”key 的闭包。
# 实际上,如果工厂函数需要 key,defaultdict 就不太适合。
# 更实际的用法是:工厂函数返回一个 *固定* 的默认值,或者一个可以 *后续* 填充的结构。
# 让我们换一个更实际的延迟计算例子,默认值是一个可以被填充的空列表
lazy_data = defaultdict(list)
# 假设我们后续会填充数据,但初始访问时是空列表
lazy_data['user_activity'].append('login')
print(f"延迟数据: {lazy_data}")这个例子有点跑偏了,因为
defaultdict
None
dict.setdefault()
__missing__
潜在的陷阱:
意外的键添加: 这是最常见的“坑”。当你仅仅是想检查一个键是否存在,或者想看看它的值是什么,但这个键恰好不存在时,
defaultdict
my_data = defaultdict(int)
print(f"字典初始状态: {my_data}") # {}
_ = my_data['non_existent_key'] # 访问,键被添加
print(f"访问后字典状态: {my_data}") # {'non_existent_key': 0}如果你期望的是一个只读的字典,或者不希望字典结构被随意修改,这可能会导致一些难以察觉的副作用。在这种情况下,使用普通
dict
get()
key in my_dict
默认值的类型不匹配: 有时候,你可能希望某个键的值是一个
int
list
defaultdict
# 比如,你想统计单词,也想记录出现过的句子 # 这是做不到的,因为 defaultdict(int) 只能处理 int 类型的默认值 # 你不能让它在需要时返回 int,在需要时返回 list # word_stats = defaultdict(int) # 或者 defaultdict(list) # 这时候你就需要用普通 dict,或者更复杂的结构
遇到这种需求,你可能需要一个普通的
dict
defaultdict(lambda: {'count': 0, 'sentences': []})序列化问题: 当你尝试用
json.dumps()
defaultdict
dict
import json
my_dd = defaultdict(int)
my_dd['a'] = 1
my_dd['b'] = 2
# print(json.dumps(my_dd)) # 会报错:TypeError: Object of type defaultdict is not JSON serializable
print(json.dumps(dict(my_dd))) # 正确的做法
# 输出: {"a": 1, "b": 2}这是因为
defaultdict
总的来说,
defaultdict
以上就是python中defaultdict怎么使用?的详细内容,更多请关注php中文网其它相关文章!
python怎么学习?python怎么入门?python在哪学?python怎么学才快?不用担心,这里为大家提供了python速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号