Pythonの辞書の欠損キー操作:setdefaultとdefaultdict
Pythonで辞書に存在しないキーで操作する際は、get()
、setdefault()
、defaultdict()
などのメソッドを用いると良い。
get()
による欠損キーへのアクセスは以下を参照。
setdefault()
とdefaultdict()
はよく似た挙動をするが、できる限りdefaultdict()
を使う方が望ましい。
以下では、foods
という辞書がvegetable
などのカテゴリーをキーとして、set()
内にcarrot
のような具体的な食材を保持している状況を考える。
foods = { "vegetable": {"carrot"}, "drink": {"water", "coffee"} }
まだ存在しないキーfruits
に新しい食材orange
を追加してみる。
get()
による値の追加
get()
メソッドはキーが存在しなかった場合に返す値を第二引数に設定できる。新しいキーfruits
が存在しなかった場合、空のセットを返しorange
をセットに追加し、fruits
に対して再代入する。
fruits = foods.get("fruits", set()) fruits.add("orange") foods["fruits"] = fruits print(foods)
get()
による値の追加
setdefault()
メソッドを使うと、先ほどの処理を1行で書くことができる。
foods.setdefault("fruits", set()).add("orange") print(foods)
setdefault
よりdefaultdict
を使おう
setdefault()
によりコードはシンプルになったが、場合によっては効率的でないことがある。例えば、次のようなクラスのインスタンスが持つ辞書によって、動的に内部状態を管理することを考える。
class Foods: def __init__(self): self.data = {} def add(self, category, food): self.data.setdefault(category, set()).add(food)
このクラスのユーザーは以下のように値を追加することができる。
foods = Foods() foods.add("fruits", "orange") foods.add("bread", "bagel") print(foods.data) # {'fruits': {'orange'}, 'bread': {'bagel'}}
しかし問題点がひとつある。foods.add()
が呼ばれるたびに、キーの欠損の有無に関わらず、必ず一度set
インスタンスの作成が行われている。コストのかかる余分なインスタンスの割り付けを回避するために、defaultdict
クラスを使うと良い。
組み込みモジュールcollectinos
のdefaultdict
クラスには、キーが存在しない場合のデフォルト値生成関数を指定することができる。これにより、キーが存在しない場合に限り、デフォルト値の生成が実行される。defaultdict
を使ってFoods
クラスを書き換える。
from collections import defaultdict class Foods: def __init__(self): self.data = defaultdict(set) def add(self, category, food): self.data[category].add(food)
使用方法はsetdefault()
のときと同じであるが、内部のメモリ効率が向上している。
foods = Foods() foods.add("fruits", "orange") foods.add("bread", "bagel") print(foods.data) # defaultdict(<class 'set'>, {'fruits': {'orange'}, 'bread': {'bagel'}})