pin_drop当前位置:知识文库 ❯ 图文
Python defaultdict默认字典详解 - 数据分组与嵌套字典教程
一、概述
defaultdict 是 collections 模块中的默认字典类,它是 dict 的子类,在访问不存在的键时自动调用工厂函数生成默认值,而非引发 KeyError。defaultdict 消除了手动检查键是否存在或使用 setdefault() 的繁琐代码,使得分组、聚合、嵌套字典等操作更加简洁优雅。
二、语法
代码示例
from collections import defaultdict
# 创建defaultdict
dd = defaultdict(default_factory)
# 常用工厂函数
dd = defaultdict(list) # 默认值为空列表
dd = defaultdict(int) # 默认值为0
dd = defaultdict(set) # 默认值为空集合
dd = defaultdict(str) # 默认值为空字符串
dd = defaultdict(lambda: "N/A") # 自定义默认值三、参数说明
常用工厂函数及其默认值:
四、返回值
-
构造函数返回
defaultdict对象 -
访问不存在的键时,返回
default_factory()的返回值 -
default_factory属性返回当前工厂函数
五、代码示例
示例1:基本使用与对比
代码示例
from collections import defaultdict
# 普通dict的问题
data = [("水果", "苹果"), ("蔬菜", "白菜"), ("水果", "香蕉")]
# 方式1:普通dict需要判断键是否存在
groups_dict = {}
for category, item in data:
if category not in groups_dict:
groups_dict[category] = []
groups_dict[category].append(item)
print(f"普通dict: {groups_dict}")
# 方式2:使用setdefault
groups_setdefault = {}
for category, item in data:
groups_setdefault.setdefault(category, []).append(item)
print(f"setdefault: {groups_setdefault}")
# 方式3:使用defaultdict(最简洁)
groups_dd = defaultdict(list)
for category, item in data:
groups_dd[category].append(item)
print(f"defaultdict: {dict(groups_dd)}")输出:
代码示例
普通dict: {'水果': ['苹果', '香蕉'], '蔬菜': ['白菜']}
setdefault: {'水果': ['苹果', '香蕉'], '蔬菜': ['白菜']}
defaultdict: {'水果': ['苹果', '香蕉'], '蔬菜': ['白菜']}示例2:不同工厂函数的应用
代码示例
from collections import defaultdict
# int工厂函数:计数器
counter = defaultdict(int)
words = ["apple", "banana", "apple", "cherry", "banana", "apple"]
for word in words:
counter[word] += 1
print(f"计数器: {dict(counter)}")
# set工厂函数:去重分组
unique_groups = defaultdict(set)
pairs = [("A", 1), ("A", 2), ("B", 1), ("A", 1), ("B", 3)]
for key, value in pairs:
unique_groups[key].add(value)
print(f"去重分组: {dict(unique_groups)}")
# 自定义工厂函数
config = defaultdict(lambda: "未配置")
config["host"] = "localhost"
print(f"\n已配置的键: {config['host']}")
print(f"未配置的键: {config['port']}")输出:
代码示例
计数器: {'apple': 3, 'banana': 2, 'cherry': 1}
去重分组: {'A': {1, 2}, 'B': {1, 3}}
已配置的键: localhost
未配置的键: 未配置示例3:嵌套defaultdict与多级分组
代码示例
from collections import defaultdict
# 嵌套defaultdict:二维分组
def nested_dict():
"""创建嵌套的defaultdict"""
return defaultdict(list)
# 按年份和月份分组
sales_data = [
("2024", "01", "产品A", 100),
("2024", "01", "产品B", 200),
("2024", "02", "产品A", 150),
("2023", "12", "产品A", 80),
("2023", "12", "产品B", 120),
]
# 二级分组
sales_by_month = defaultdict(nested_dict)
for year, month, product, amount in sales_data:
sales_by_month[year][month].append((product, amount))
# 输出结果
print("销售数据分组:")
for year in sorted(sales_by_month.keys()):
print(f" {year}年:")
for month in sorted(sales_by_month[year].keys()):
items = sales_by_month[year][month]
total = sum(a for _, a in items)
print(f" {month}月: {len(items)}笔, 总额{total}")
# 多级聚合:使用defaultdict(int)汇总
yearly_totals = defaultdict(int)
for year, month, product, amount in sales_data:
yearly_totals[year] += amount
print(f"\n年度汇总: {dict(yearly_totals)}")输出:
代码示例
销售数据分组:
2023年:
12月: 2笔, 总额200
2024年:
01月: 2笔, 总额300
02月: 1笔, 总额150
年度汇总: {'2024': 450, '2023': 200}六、实际应用场景
-
数据分组:按类别、日期、地区等维度对数据进行分组聚合
-
计数统计:使用
defaultdict(int)实现简单的计数器 -
嵌套数据结构:构建多层嵌套的字典结构,无需逐层初始化
七、注意事项
注意1:
defaultdict在访问不存在的键时会自动创建该键并插入默认值,这可能导致意外的键被创建。如果只想查询而不创建,应使用get()方法或in运算符。
注意2:
defaultdict的default_factory只影响__getitem__(dd[key])的行为,get()方法不受影响,仍返回None。
注意3:嵌套
defaultdict的序列化(如json.dumps())可能遇到问题,因为defaultdict不是标准dict。可使用dict()转换后再序列化。
注意4:
default_factory为None时,defaultdict的行为与普通dict相同,访问不存在的键会引发KeyError。
提示:可以使用
functools.partial或 lambda 创建更复杂的默认值工厂,如defaultdict(partial(defaultdict, int))创建嵌套计数器。
八、相关方法对比
九、小结
-
defaultdict在访问不存在的键时自动创建默认值,消除了繁琐的存在性检查 -
常用工厂函数:
list(分组)、int(计数)、set(去重分组) -
嵌套
defaultdict可构建多级数据结构,无需逐层初始化 -
注意
__getitem__会创建键,查询用get()或in,序列化前用dict()转换
十、练习题
练习1
编写一个函数 group_by_length(words),使用 defaultdict 将单词按长度分组。
练习2
编写一个函数 build_index(docs),使用 defaultdict(set) 构建倒排索引,输入文档列表,输出词到文档编号的映射。
练习3
编写一个三级嵌套的 defaultdict,实现按"年份->月份->类别"汇总销售数据,并支持按任意层级查询汇总值。
常见问题
defaultdict和普通dict的性能有差异吗?
在大多数情况下,defaultdict 的性能略优于普通 dict 加 setdefault() 的组合,因为工厂函数的调用在 C 层完成。但当不需要自动创建默认值时,普通 dict 的 get() 方法性能最佳。
defaultdict的default_factory可以动态修改吗?
可以。defaultdict 的 default_factory 是一个可读写属性,可以随时修改。例如:dd.default_factory = set 会将默认值从列表改为集合。
如何将defaultdict转换为JSON?
json.dumps() 不能直接序列化 defaultdict。需要先转换为普通字典:json.dumps(dict(dd))。对于嵌套的 defaultdict,可以使用递归转换。
defaultdict访问键时一定会创建新键吗?
是的,使用 dd[key] 访问不存在的键一定会创建该键。如果只想查询而不创建,应该使用 dd.get(key) 或 key in dd。
如何创建无限嵌套的defaultdict?
可以使用 lambda 自引用:infinite_dd = lambda: defaultdict(infinite_dd),然后 dd = defaultdict(infinite_dd)。这样可以创建任意深度的嵌套结构。
本文涉及AI创作
内容由AI创作,请仔细甄别