Pythonの辞書で条件に合致する要素を削除する


d = {"a": 1, "b": 0, "c": 1}

上記のような辞書があったとして、値が0である要素のみ削除したいとする。
直感的に以下のコードを書いてみる。

for k, v in d.items():
    if v == 0:
        del d[k]

動かすと、以下のエラーが発生する。

RuntimeError: dictionary changed size during iteration

言っていることは分かるが、納得できなくて狂いそう・・・!(静かなる怒り)
対処法として、辞書と直接紐づかないiterableな変数を用意してfor文を回すことを考える。
具体的には、値が0であるキーのリストでfor文を回す。
ここでリストの内包表記が使えると考えられるが、Python触り始めて半年以上経つのに、
オレにはまだ内包表記が・・・ よく分からんのよ・・・!
@ITの記事が分かりやすかった(小並感)。以下のコードは引用。

some_var = [expression for item in iterable_obj if condition]
some_var = []
for item in iterable_obj:
    if condition:
        some_var.append(expression)

この2つのコードが同じであるとのこと。
後者のコードを今回やりたいことに当てはめると、以下のコードになる。

target_keys = []
for key in d.keys():
    if d[key] == 0:
        target_keys.append(key)

これをリストの内包表記に変換する。

target_keys = [key for key in d.keys() if d[key] == 0]

というわけで、辞書から値が0である要素を削除するためのコードは以下の通り。

for target_key in [key for key in d.keys() if d[key] == 0]:
    del d[target_key]

・・・ヨシ!