defaultdictは存在しないキーにアクセスした際に自動的にデフォルト値を設定する機能を持つPythonの辞書型です。単語のカウント、データのグループ化、ネスト構造の作成など多くの場面で活躍します。本記事では、defaultdictの基本から応用まで、具体的なコード例を交えて解説します。通常のdictと比較しながら、どのようにコードを簡潔にできるかを示し、実際の開発で役立つ使い方を紹介します。
defaultdictとは
defaultdictは存在しないキーにアクセスした際に自動的にデフォルト値を設定する機能を持つ、Pythonの標準ライブラリcollectionsモジュールのクラスです。通常の辞書型(dict)を拡張したもので、コードの簡潔さと安全性を高めます。
dictとdefaultdictの比較
特徴 | dict | defaultdict |
---|---|---|
存在しないキーへのアクセス | KeyErrorが発生する | 指定したデフォルト値を返し、そのキーと値のペアを辞書に追加する |
エラーハンドリング | try-exceptが必要 | 不要 |
コード量 | キーの存在確認が必要 | キーの存在確認が不要 |
初期化 | 明示的に行う必要がある | 自動的に行われる |
defaultdictの主なメリット
- コードの簡潔化: キーの存在確認や初期化のコードが不要になる
- エラー防止: 存在しないキーへのアクセスによるKeyErrorを防げる
- データ集計の効率化: カウンターやグループ化などの処理が簡単に書ける
- ネスト構造の簡易化: 多次元の辞書構造を簡単に扱える
- 動的なデータ構造: キーが動的に増えていく処理に最適
コード例による比較
通常のdictで存在しないキーにアクセスするとエラーが発生します。
# 通常のdictで存在しないキーにアクセスする例
normal_dict = {}
try:
print(normal_dict["存在しないキー"])
except KeyError as e:
print(f"エラーが発生: {e}")
# 出力例: エラーが発生: '存在しないキー'
defaultdictでは存在しないキーにアクセスしても自動的にデフォルト値が設定されます。
# defaultdictで存在しないキーにアクセスする例
from collections import defaultdict
default_dict = defaultdict(int) # デフォルト値として0を返す
print(default_dict["存在しないキー"]) # 出力例: 0
print(default_dict) # 出力例: defaultdict(<class 'int'>, {'存在しないキー': 0})
単語カウントの例で両者を比較すると違いが明確になります。
# dictで単語カウントを行う例
text = "apple banana apple"
word_count_dict = {}
for word in text.split():
if word in word_count_dict:
word_count_dict[word] += 1
else:
word_count_dict[word] = 1
print(word_count_dict)
# 出力例: {'apple': 2, 'banana': 1}
# defaultdictで単語カウントを行う例
from collections import defaultdict
text = "apple banana apple"
word_count_defaultdict = defaultdict(int)
for word in text.split():
word_count_defaultdict[word] += 1 # 存在確認不要で直接加算できる
print(dict(word_count_defaultdict))
# 出力例: {'apple': 2, 'banana': 1}
このように、defaultdictを使うことで特に要素の集計やグループ化など、キーが動的に増えていく処理を簡潔に書くことができます。
構文
基本的な使い方
defaultdictを使うには3つの簡単なステップがあります。
- まずcollectionsモジュールからdefaultdictをインポートします
from collections import defaultdict
- default_factory(デフォルト値を生成する関数)を指定してdefaultdictを作成します
# 基本形: defaultdict(default_factory)
my_dict = defaultdict(int) # intを指定すると、存在しないキーに対して0を返す
- 通常の辞書と同じように使用します
# 存在しないキーにアクセスしても自動的にデフォルト値が設定される
my_dict["新しいキー"] += 5 # 自動的に0が設定され、その後5が加算される
print(my_dict["新しいキー"]) # 出力例: 5
default_factoryの種類と返り値
default_factoryには様々な型や関数を指定でき、それによって存在しないキーにアクセスした際の返り値が決まります。
default_factory | 返り値 | 使用例 | 結果 |
---|---|---|---|
int | 0 | d = defaultdict(int); print(d["x"]) | 0 |
float | 0.0 | d = defaultdict(float); print(d["x"]) | 0.0 |
str | 空文字列 | d = defaultdict(str); print(d["x"]) | “” |
list | 空リスト | d = defaultdict(list); d["x"].append(1); print(d["x"]) | [1] |
dict | 空辞書 | d = defaultdict(dict); d["x"]["y"] = 1; print(d["x"]) | {“y”: 1} |
set | 空集合 | d = defaultdict(set); d["x"].add(1); print(d["x"]) | {1} |
default_factoryの具体的な使用例
整数のデフォルト値(0)を使用する例です。
# intを指定した例(カウンター)
from collections import defaultdict
counter = defaultdict(int)
words = ["apple", "banana", "apple", "orange"]
for word in words:
counter[word] += 1 # 初めて出現する単語も += 1 が可能
print(dict(counter))
# 出力例: {'apple': 2, 'banana': 1, 'orange': 1}
リストのデフォルト値(空リスト)を使用する例です。
# listを指定した例(グループ化)
from collections import defaultdict
groups = defaultdict(list)
data = [("A", 1), ("B", 2), ("A", 3), ("C", 4), ("B", 5)]
for key, value in data:
groups[key].append(value) # キーが存在しなくても.append()が可能
print(dict(groups))
# 出力例: {'A': [1, 3], 'B': [2, 5], 'C': [4]}
カスタムデフォルト値を使用する例です。
# lambdaを使ったカスタムデフォルト値の例
from collections import defaultdict
# "不明"をデフォルト値とする辞書
user_info = defaultdict(lambda: "不明")
user_info["user1"] = "太郎"
print(user_info["user1"]) # 出力例: 太郎
print(user_info["user2"]) # 出力例: 不明
利用例
単語の出現回数をカウントする
単語の出現回数をカウントする場合、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は、存在しないキーにアクセスした際に自動的にデフォルト値を設定する機能を持つPythonの辞書型です。以下のような場面で特に役立ちます。
- 単語カウントなどのデータ集計
- 共通の特性を持つデータのグループ化
- 多次元の辞書構造の簡易化
- キーに対する初期値の自動設定
通常のdictと比較して、コードの簡潔さとエラー処理の簡略化が大きなメリットです。ただし、意図しないキーの作成によるメモリ消費には注意が必要です。
適切なdefault_factory(int、list、dictなど)を選ぶことで、様々なデータ処理を効率化できます。defaultdictを活用することで、Pythonプログラミングの生産性と可読性を向上させることができます。