Pythonでのdeafaultdictの使い方を解説

本記事では、Pythonでのdefaultdictの使い方を解説します。defaultdictを使うと、存在しないキーにアクセスした際のエラーを防ぎ、コードをより簡潔に書くことができます。

defaultdictとは

defaultdictはPythonの標準ライブラリcollectionsモジュールに含まれるクラスで、通常の辞書型(dict)を拡張したものです。

dictとdefaultdictの最大の違いは、存在しないキーにアクセスした際の挙動です。

  • dict: 存在しないキーにアクセスするとKeyErrorが発生します
  • defaultdict: 存在しないキーにアクセスすると、指定したデフォルト値を返し、そのキーと値のペアを辞書に追加します

以下に具体的なコード例で比較してみましょう。

# 通常のdictの場合
normal_dict = {}
try:
    print(normal_dict["存在しないキー"])
except KeyError as e:
    print(f"エラーが発生: {e}")
    # 出力例: エラーが発生: '存在しないキー'

# defaultdictの場合
from collections import defaultdict
default_dict = defaultdict(int)  # デフォルト値として0を返す
print(default_dict["存在しないキー"])  # 出力例: 0
print(default_dict)  # 出力例: defaultdict(<class 'int'>, {'存在しないキー': 0})

この挙動の違いにより、defaultdictは特に要素の集計やグループ化など、キーが動的に増えていく処理で非常に便利です。

構文

defaultdictを使用するには、まずcollectionsモジュールからインポートする必要があります。

from collections import defaultdict

基本的な構文は次のとおりです。

# defaultdict(default_factory)
my_dict = defaultdict(default_factory)

ここでdefault_factoryは、存在しないキーにアクセスした際にデフォルト値を生成する関数です。以下はよく使われるdefault_factoryの例です。

  • int: 0を返す
  • float: 0.0を返す
  • str: 空文字列を返す
  • list: 空リストを返す
  • dict: 空辞書を返す
  • set: 空集合を返す
  • lambda関数: カスタムデフォルト値を返す

利用例

単語の出現回数をカウントする

単語の出現回数をカウントする場合、defaultdictを使うと簡潔に書けます。

from collections import defaultdict

text = "apple banana apple orange banana apple"
word_count = defaultdict(int)

for word in text.split():
    word_count[word] += 1

print(word_count)
# 出力例: defaultdict(<class 'int'>, {'apple': 3, 'banana': 2, 'orange': 1})

通常のdictを使った場合、キーの存在チェックが必要です。

# 通常のdictで同じ処理を行う場合(比較用)
text = "apple banana apple orange banana apple"
word_count = {}

for word in text.split():
    if word in word_count:
        word_count[word] += 1  # キーの存在確認が必要
    else:
        word_count[word] = 1   # 存在しない場合は初期化が必要

グループ化する

名前をアルファベットの頭文字でグループ化する例です。

from collections import defaultdict

names = ["Alice", "Bob", "Charlie", "David", "Alex", "Barbara"]
grouped_names = defaultdict(list)

for name in names:
    grouped_names[name[0]].append(name) # 頭文字をキーにしてリストに名前を追加

print(grouped_names)
# 出力例: defaultdict(<class 'list'>, {'A': ['Alice', 'Alex'], 'B': ['Bob', 'Barbara'], 'C': ['Charlie'], 'D': ['David']})

ネストしたdefaultdictの作成

二次元以上の構造を扱う場合にも便利です。

from collections import defaultdict

# 二次元のdefaultdict
nested_dict = defaultdict(lambda: defaultdict(int))

# データの追加
nested_dict["user1"]["apple"] = 5
nested_dict["user1"]["banana"] = 2
nested_dict["user2"]["apple"] = 1

# 存在しないキーでもエラーにならない
print(nested_dict["user3"]["orange"])  # 出力例: 0

print(dict(nested_dict))
# 出力例: {'user1': defaultdict(<class 'int'>, {'apple': 5, 'banana': 2}), 'user2': defaultdict(<class 'int'>, {'apple': 1}), 'user3': defaultdict(<class 'int'>, {'orange': 0})}

独自のデフォルト値を設定する

lambdaを使って独自のデフォルト値を設定できます。

from collections import defaultdict

# "Unknown"をデフォルト値とする辞書
my_dict = defaultdict(lambda: "Unknown")
my_dict["known_key"] = "Known Value"

print(my_dict["known_key"])  # 出力例: Known Value
print(my_dict["unknown_key"])  # 出力例: Unknown

注意点

メモリ使用量に注意

defaultdictは存在しないキーにアクセスするたびに新しいエントリを作成するため、無制限にキーが増える可能性があります。特に大量のデータを扱う場合はメモリ使用量に注意しましょう。

from collections import defaultdict

# 誤った使用例
my_dict = defaultdict(list)

# typoによる意図しないキーの作成
my_dict["correct_key"].append(1)
my_dict["corect_key"].append(2)  # タイプミス

print(len(my_dict))  # 出力例: 2 (意図せず2つのキーができてしまった)

デフォルト値のミュータブル性に注意

mutable(変更可能)なオブジェクトをデフォルト値にする場合、全てのキーで同じオブジェクトを参照することはありません。各キーに対して新しいオブジェクトが作成されます。

from collections import defaultdict

# 各キーに対して新しいリストが作成される
my_dict = defaultdict(list)
my_dict["key1"].append(1)
my_dict["key2"].append(2)

print(my_dict["key1"])  # 出力例: [1]
print(my_dict["key2"])  # 出力例: [2]

default_factoryにNoneを指定するとエラーになる

default_factoryにNoneを指定すると、通常のdictと同様に存在しないキーにアクセスした際にKeyErrorが発生します。

from collections import defaultdict

my_dict = defaultdict(None)
try:
    print(my_dict["non_existent_key"])
except KeyError as e:
    print(f"エラーが発生しました: {e}")
    # 出力例: エラーが発生しました: 'non_existent_key'

まとめ

defaultdictは以下のような状況で特に有用です。

  1. 存在しないキーに対する処理を簡略化したい場合
  2. 集計処理やグループ化を行う場合
  3. ネストした辞書構造を扱う場合
  4. キーに対して初期値を自動的に設定したい場合

通常のdictと比較して、コードの可読性を高め、エラーハンドリングを減らすことができます。ただし、意図しないキーの作成によるメモリ消費に注意する必要があります。

Pythonのデータ処理において、defaultdictは非常に強力なツールであり、適切に使いこなすことでコードの品質を向上させることができます。

タイトルとURLをコピーしました