Python 辞書の「列挙」順が不定だという当然の話

初心者じゃあるまいし、てミスをしでかした、の巻。

「Python 辞書の「列挙」順は不定である」というのはまぁ「仕様」だし、当然のことなんだけれど、何を思ったか、

1 d[list(d.keys())[0]]

なんてことをやらかしてた。多分脳が「まずは実装」モードのオートメーション状態だったものと思われる。これ、xml を辞書にしたこんな:

1 {"@RelativePath": "../hoge.h", "FileConfiguration": {...}}

から「”@RelativePath”」を取るのが責務の場所で、おそらく「相対パス(RelativePath)でないことはないの?」と咄嗟に考えたものと思われる。けどだったら get か pop の fallback 引数を使うのが筋だよなぁ。

でこの間違いに気付くまでに非常に時間がかかってしまったのはそう、「不定」だから。「不定」というのにも色々あって、「同じ入力ならいつでも同じ順序にはなる」という、「あなたの意図順ではない」という意味でしかない「不定」と、本当に実行のたびに結果がランダムになる本物の「不定」がある。後者は無論結果論であって、同じことではあるんだけれど、プログラマーから見た印象はかなり違う。特にその「ランダム」に強い偏りがある場合だ。つまり「100回に98回は期待通り」のような。こうなると事象を再現させるだけで苦労するハメになり、だから原因もなかなか見つけられない。

シンプルな再現パターンを書きたかったがまさに「100回に98回は期待通り」なのかあるいは何か型によるのかわからないが、こんな:

1 d = {"a": 1, "b": 2}
2 list(d.keys())

はどうも同じ python セッション内では常に同一順みたいだ。確かインタプリタ実行時点で何かハッシュの制御してた気がするな。多分そのせいだな。今ちょっと試したら、「python 3.5 ではたまたま常に “b”, “a”」「python 2.7 ではたまたま常に “a”, “b”」だったが、別の対話セッションでは違う結果になる、よな、多分。(ハッシュの仕様はセキュリティ関連(予測不可能にするための)だったと思うんだけど、2.7 だとマイクロバージョンが小さいもの、例えば 2.7.2 とかには入ってなかったんじゃなかったかな、確か。)

なんにせよ「雑に書くモードの場合でも踏み外してはいけないコト」は踏み外しちゃいかんね。おそらく1秒未満の判断でこんなバカなコードを書いちゃったんだろうけれど。