如何在 Python 中创建默认值为 0 的 defaultdict

PythonPythonBeginner
立即练习

💡 本教程由 AI 辅助翻译自英文原版。如需查看原文,您可以 切换至英文原版

简介

在本教程中,我们将探索 Python 中的 defaultdict 数据结构,它是标准字典的一个强大变体,能够优雅地处理缺失键的情况。具体来说,我们将学习如何创建一个默认值为 0 的 defaultdict,这在 Python 程序中进行计数和累加值时特别有用。

在本实验结束时,你将理解什么是 defaultdict,如何创建一个默认值为 0 的 defaultdict,以及如何在实际场景中应用它来编写更优雅且抗错误的代码。


Skills Graph

%%%%{init: {'theme':'neutral'}}%%%% flowchart RL python(("Python")) -.-> python/ControlFlowGroup(["Control Flow"]) python(("Python")) -.-> python/DataStructuresGroup(["Data Structures"]) python(("Python")) -.-> python/FunctionsGroup(["Functions"]) python(("Python")) -.-> python/PythonStandardLibraryGroup(["Python Standard Library"]) python/ControlFlowGroup -.-> python/conditional_statements("Conditional Statements") python/DataStructuresGroup -.-> python/dictionaries("Dictionaries") python/FunctionsGroup -.-> python/function_definition("Function Definition") python/FunctionsGroup -.-> python/default_arguments("Default Arguments") python/PythonStandardLibraryGroup -.-> python/data_collections("Data Collections") subgraph Lab Skills python/conditional_statements -.-> lab-397967{{"如何在 Python 中创建默认值为 0 的 defaultdict"}} python/dictionaries -.-> lab-397967{{"如何在 Python 中创建默认值为 0 的 defaultdict"}} python/function_definition -.-> lab-397967{{"如何在 Python 中创建默认值为 0 的 defaultdict"}} python/default_arguments -.-> lab-397967{{"如何在 Python 中创建默认值为 0 的 defaultdict"}} python/data_collections -.-> lab-397967{{"如何在 Python 中创建默认值为 0 的 defaultdict"}} end

理解常规字典的问题

在深入探讨 defaultdict 之前,让我们先了解一下常规字典的局限性,而 defaultdict 正是为解决这些局限性而设计的。

KeyError 问题

在 Python 中,标准字典(dict)用于存储键值对。然而,当你尝试访问常规字典中不存在的键时,Python 会引发 KeyError

让我们创建一个简单的示例来演示这个问题:

  1. 在编辑器中创建一个名为 regular_dict_demo.py 的新文件:
## 创建一个常规字典来统计水果数量
fruit_counts = {}

## 尝试增加 'apple' 的计数
try:
    fruit_counts['apple'] += 1
except KeyError:
    print("KeyError: 'apple' 键在字典中不存在")

## 使用常规字典的正确方法
if 'banana' in fruit_counts:
    fruit_counts['banana'] += 1
else:
    fruit_counts['banana'] = 1

print(f"水果计数: {fruit_counts}")
  1. 在终端中运行脚本:
python3 regular_dict_demo.py

你应该会看到类似以下的输出:

KeyError: 'apple' 键在字典中不存在
水果计数: {'banana': 1}
常规字典演示

如你所见,尝试增加不存在的键的计数会导致错误。常见的解决方法是在尝试访问键之前检查它是否存在,这会导致代码更加冗长。

这就是 defaultdict 发挥作用的地方——它在访问时通过使用默认值自动创建缺失的键来处理这个问题。

介绍默认值为 0 的 defaultdict

既然我们已经了解了常规字典的问题,那么让我们来学习如何使用 defaultdict 来解决它。

什么是 defaultdict?

defaultdict 是 Python 内置 dict 类的一个子类,它接受一个函数(称为“默认工厂函数”)作为其第一个参数。当访问一个不存在的键时,defaultdict 会自动使用默认工厂函数返回的值创建该键。

创建默认值为 0 的 defaultdict

让我们创建一个 defaultdict,为任何缺失的键提供默认值 0:

  1. 在编辑器中创建一个名为 default_dict_zero.py 的新文件:
## 首先,从 collections 模块导入 defaultdict 类
from collections import defaultdict

## 方法 1:使用 int 作为默认工厂函数
## 不带参数调用 int() 函数会返回 0
counter = defaultdict(int)

print("计数器的初始状态:", dict(counter))

## 访问一个尚不存在的键
print("'apple' 的值(之前):", counter['apple'])

## 增加计数
counter['apple'] += 1
counter['apple'] += 1
counter['banana'] += 1

print("'apple' 的值(之后):", counter['apple'])
print("操作后的字典:", dict(counter))

## 方法 2:使用 lambda 函数(另一种方法)
counter2 = defaultdict(lambda: 0)

print("\n使用 lambda 函数:")
print("'cherry' 的值(之前):", counter2['cherry'])
counter2['cherry'] += 5
print("'cherry' 的值(之后):", counter2['cherry'])
print("操作后的字典:", dict(counter2))
  1. 在终端中运行脚本:
python3 default_dict_zero.py
默认字典为零

你应该会看到类似以下的输出:

计数器的初始状态: {}
'apple' 的值(之前): 0
'apple' 的值(之后): 2
操作后的字典: {'apple': 2, 'banana': 1}

使用 lambda 函数:
'cherry' 的值(之前): 0
'cherry' 的值(之后): 5
操作后的字典: {'cherry': 5}

它是如何工作的

当我们创建 defaultdict(int) 时,我们告诉 Python 使用 int() 函数作为默认工厂函数。不带参数调用时,int() 返回 0,这将成为任何缺失键的默认值。

同样,我们可以使用一个 lambda 函数 lambda: 0,它在被调用时只返回 0。

注意我们如何能够直接访问并增加之前不存在的键的值,而不会出现任何错误。

实际应用案例:统计单词频率

默认值为 0 的 defaultdict 最常见的应用之一就是统计频率。让我们通过实现一个单词频率计数器来演示这个实际应用案例。

  1. 在编辑器中创建一个名为 word_counter.py 的新文件:
from collections import defaultdict

def count_word_frequencies(text):
    ## 创建一个默认值为 0 的 defaultdict
    word_counts = defaultdict(int)

    ## 将文本拆分成单词并转换为小写
    words = text.lower().split()

    ## 清理每个单词(去除标点符号)并统计出现次数
    for word in words:
        ## 去除常见标点符号
        clean_word = word.strip('.,!?:;()"\'')
        if clean_word:  ## 跳过空字符串
            word_counts[clean_word] += 1

    return word_counts

## 使用示例文本测试函数
sample_text = """
Python 很棒!Python 很容易学,而且 Python 非常强大。
使用 Python,你可以创建 Web 应用程序、分析数据、构建游戏,
还能自动化任务。Python 的语法清晰易读。
"""

word_frequencies = count_word_frequencies(sample_text)

## 打印结果
print("单词频率:")
for word, count in sorted(word_frequencies.items()):
    print(f"  {word}: {count}")

## 找出最常见的单词
print("\n最常见的单词:")
sorted_words = sorted(word_frequencies.items(), key=lambda x: x[1], reverse=True)
for word, count in sorted_words[:5]:  ## 前 5 个单词
    print(f"  {word}: {count}")
  1. 在终端中运行脚本:
python3 word_counter.py

你应该会看到类似以下的输出:

单词频率:
  amazing: 1
  analyze: 1
  and: 3
  applications: 1
  automate: 1
  build: 1
  can: 1
  clear: 1
  create: 1
  data: 1
  easy: 1
  games: 1
  is: 4
  learn: 1
  powerful: 1
  python: 4
  python's: 1
  readable: 1
  syntax: 1
  tasks: 1
  to: 1
  very: 1
  web: 1
  with: 1
  you: 1

最常见的单词:
  python: 4
  is: 4
  and: 3
  amazing: 1
  easy: 1

这是如何工作的

  1. 我们创建一个 defaultdict(int) 来存储单词计数,默认值为 0
  2. 我们处理文本中的每个单词,清理标点符号
  3. 我们使用 word_counts[word] += 1 简单地增加每个单词的计数
  4. 对于首次出现的单词,会自动分配默认值 0

这种方法比使用带有存在检查的常规字典要简洁得多且效率更高。

使用默认值为 0 的 defaultdict 的好处

  • 简化代码:无需在增加计数前检查键是否存在
  • 减少代码行数:去除了样板式的键存在检查
  • 减少错误:消除了潜在的 KeyError 异常
  • 更具可读性:使计数逻辑更清晰、简洁

默认值为 0 的 defaultdict 对于任何涉及计数或累加值的任务都特别有用,例如:

  • 频率分析
  • 直方图
  • 按类别聚合数据
  • 跟踪日志或数据集中的出现次数

性能比较:defaultdict 与常规字典

让我们比较一下默认值为 0 的 defaultdict 和常规字典在常见计数任务中的性能。这将帮助你了解何时选择使用其中一个。

  1. 在编辑器中创建一个名为 performance_comparison.py 的新文件:
import time
from collections import defaultdict

def count_with_regular_dict(data):
    """使用常规字典统计频率。"""
    counts = {}
    for item in data:
        if item in counts:
            counts[item] += 1
        else:
            counts[item] = 1
    return counts

def count_with_defaultdict(data):
    """使用默认值为 0 的 defaultdict 统计频率。"""
    counts = defaultdict(int)
    for item in data:
        counts[item] += 1
    return counts

## 生成测试数据 - 0 到 99 之间的随机数列表
import random
random.seed(42)  ## 为了可重复的结果
data = [random.randint(0, 99) for _ in range(1000000)]

## 测量常规字典方法的时间
start_time = time.time()
result1 = count_with_regular_dict(data)
regular_dict_time = time.time() - start_time

## 测量 defaultdict 方法的时间
start_time = time.time()
result2 = count_with_defaultdict(data)
defaultdict_time = time.time() - start_time

## 打印结果
print(f"常规字典时间: {regular_dict_time:.4f} 秒")
print(f"defaultdict 时间:        {defaultdict_time:.4f} 秒")
print(f"defaultdict 快 {regular_dict_time/defaultdict_time:.2f} 倍")

## 验证两种方法的结果是否相同
assert dict(result2) == result1, "计数结果不匹配!"
print("\n两种方法产生了相同的计数结果 ✓")

## 打印一些计数结果示例
print("\n计数结果示例(前 5 项):")
for i, (key, value) in enumerate(sorted(result1.items())):
    if i >= 5:
        break
    print(f"  数字 {key}: {value} 次出现")
  1. 在终端中运行脚本:
python3 performance_comparison.py

你应该会看到类似以下的输出:

常规字典时间: 0.1075 秒
defaultdict 时间:        0.0963 秒
defaultdict 快 1.12 倍

两种方法产生了相同的计数结果 ✓

计数结果示例(前 5 项):
  数字 0: 10192 次出现
  数字 1: 9949 次出现
  数字 2: 9929 次出现
  数字 3: 9881 次出现
  数字 4: 9922 次出现

注意:根据你的系统,你得到的精确计时结果可能会有所不同。

结果分析

性能比较表明,在计数任务中,defaultdict 通常比常规字典更快,原因如下:

  1. 它无需进行键存在检查(if key in dictionary
  2. 它减少了每个项目的字典查找次数
  3. 它简化了代码,这可能会使 Python 解释器进行优化

除了性能优势外,defaultdict 还具有以下优点:

  • 代码简洁性:代码更简洁且易读
  • 认知负担减轻:你无需记住处理缺失键的情况
  • 出错机会减少:代码越少,出错的机会就越少

这使得默认值为 0 的 defaultdict 成为 Python 中计数操作、频率分析和其他累加任务的绝佳选择。

总结

在本实验中,你已经了解了 Python 的 defaultdict 以及如何使用默认值 0 来使用它。让我们回顾一下我们所涵盖的内容:

  1. 我们确定了常规字典的局限性,即在访问不存在的键时会引发 KeyError
  2. 我们学习了如何使用 defaultdict(int)defaultdict(lambda: 0) 创建默认值为 0 的 defaultdict
  3. 我们通过实现一个单词频率计数器探索了一个实际用例
  4. 我们比较了 defaultdict 和常规字典的性能,发现 defaultdict 不仅更方便,而且在计数任务中更快

默认值为 0 的 defaultdict 是一个强大的工具,它简化了 Python 中的计数、累加和频率分析。通过自动处理缺失的键,它使你的代码更简洁、更高效且更不易出错。

这种模式通常用于:

  • 数据处理与分析
  • 自然语言处理
  • 日志分析
  • 游戏开发(用于评分系统)
  • 任何涉及计数器或累加器的场景

通过掌握默认值为 0 的 defaultdict,你在 Python 编程工具包中添加了一个重要工具,这将帮助你编写更优雅、高效的代码。