Pyhton——defaultdict的用法


整体说明

  • defaultdict 是 Python 标准库 collections 模块中的一个工具,继承自普通字典 dict
  • defaultdict 的核心特点是:访问不存在的键时,会自动创建该键并赋予默认值
    • 无需手动判断 key in dict 或使用 dict.get(key, 默认值)
  • defaultdict 的核心是 “自动处理不存在的键” ,适合以下场景:
    • 统计计数(defaultdict(int)
    • 分组聚合(defaultdict(list)/set
    • 避免频繁判断 key in dictdict.get()

defaultdict 基本用法

  • 初始化:指定“默认值工厂函数”:defaultdict 的构造函数接收一个 可调用对象(工厂函数) ,当访问不存在的键时,会调用该函数生成默认值
  • 常见的工厂函数可以是:
    • 内置类型:int(默认 0)、list(默认空列表)、set(默认空集合)、str(默认空字符串)
    • 自定义函数:返回固定值或动态生成的值
  • 可以用于解决普通字典的痛点:访问不存在的键会抛出 KeyError
    1
    2
    3
    4
    5
    6
    7
    8
    # 普通字典:访问不存在的键报错
    d = {}
    print(d["foo"]) # KeyError: 'foo'

    # defaultdict:自动创建键并赋予默认值
    from collections import defaultdict
    dd = defaultdict(int) # 默认值为 0
    print(dd["foo"]) # 输出 0,且 dd 现在是 {'foo': 0}

defaultdict 使用示例

  • 统计元素出现次数(用 int 作工厂)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    from collections import defaultdict

    words = ["apple", "banana", "apple", "orange", "banana", "apple"]
    count = defaultdict(int) # 键不存在时默认值为 0

    for word in words:
    count[word] += 1 # 无需判断键是否存在,直接累加

    print(dict(count)) # 转为普通字典:{'apple': 3, 'banana': 2, 'orange': 1}
  • 分组(用 list 作工厂):将元素按某个规则分组,值为列表(自动创建空列表,避免手动 append 时报错):

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    from collections import defaultdict

    students = [("Alice", "Math"), ("Bob", "English"), ("Alice", "Physics"), ("Bob", "Math")]
    group = defaultdict(list) # 键不存在时默认值为 []

    for name, subject in students:
    group[name].append(subject) # 直接向列表添加元素

    print(dict(group))
    # 输出:{'Alice': ['Math', 'Physics'], 'Bob': ['English', 'Math']}
  • 去重分组(用 set 作工厂):值为集合 set,自动去重:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    from collections import defaultdict

    data = [("a", 1), ("b", 2), ("a", 1), ("b", 3)]
    group = defaultdict(set) # 键不存在时默认值为 set()

    for key, val in data:
    group[key].add(val) # 集合自动去重

    print(dict(group)) # 输出:{'a': {1}, 'b': {2, 3}}
  • 自定义默认值(用自定义函数作工厂):如果需要非内置的默认值(如 None、固定字符串、动态值),可传入自定义函数:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    from collections import defaultdict

    # 自定义工厂函数:返回固定值 "unknown"
    def default_val():
    return "unknown"

    dd = defaultdict(default_val)
    print(dd["foo"]) # 输出 "unknown",dd 变为 {'foo': 'unknown'}

    # 简化:用 lambda 表达式(适合简单默认值)
    dd2 = defaultdict(lambda: None) # 默认值为 None
    print(dd2["bar"]) # 输出 None

    dd3 = defaultdict(lambda: [1, 2, 3]) # 默认值为 [1,2,3]
    print(dd3["baz"]) # 输出 [1,2,3]

特别注意 dict.fromkeys()

  • dict.fromkeys() 也能设置默认值,但会为所有键共享同一个可变对象(如列表),容易踩坑:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    # 普通 dict.fromkeys() 的坑:所有键共享同一个列表
    d = dict.fromkeys(["a", "b"], [])
    d["a"].append(1)
    print(d) # {'a': [1], 'b': [1]}(意外修改了 b 的值)

    # defaultdict 无此问题:每个键的列表是独立的
    dd = defaultdict(list)
    dd["a"].append(1)
    print(dd) # {'a': [1]}(b 未被创建)