Python 3.7から(非公式には3.6から) dict
がキーの順序を保証するようになりました(collections.OrderedDict
相当の動作になった)。
今更ながら「dict
が順序を保存するようになって良かったナァ」とシミジミ感じているので、その気持ちをダンプします。
良かったこと
例えば pandas でデータ集計をした時に DataFrame
のカラム名を日本語に直した上で順序も入れ替えたい、なんてことはあるでしょう。
Python 3.7以降では、こんな風に辞書を1つ書けばOK。
import pandas as pd
df = pd.DataFrame(...) # 何処かから DataFrame を取得済みとする。カラムは "age", "name", "salary"
# カラムの順序を "name, age, salary" にした上で、日本語に置き換えたい
mapper = {
"name": '名前',
"age": "年齢",
"salary": "年収",
}
output = df[mapper.keys()].rename(columns=mapper)
# 名前 年齢 年収
# 0 Alice 21 100
# 1 Bob 32 1200
# 2 Charlie 43 2300
Python 3.5 では、辞書の順序が保存されないので、カラムの順序が入れ替わってしまうかもしれません。
# 名前 年収 年齢
# 0 Alice 100 21
# 1 Bob 1200 32
# 2 Charlie 2300 43
カラムの順序を保存するには、別途順序を表すリストを用意するか・・・
mapper = {
"name": '名前',
"age": "年齢",
"salary": "年収",
}
keys = ["name", "age", "salary"]
output = df[keys].rename(columns=mapper)
順序を保証する OrderedDict
を使うしかありませんでした。
from collections import OrderedDict
mapper = OrderedDict([
("name", '名前'),
("age", "年齢"),
("salary", "年収"),
])
output = df[mapper.keys()].rename(columns=mapper)
でも、リストを別に用意するのDRYじゃありません。
OrderedDict
はDRYではあるんですが、見た目が「マッピング」っぽくありません。カッコが多くて書くのも面倒だし、from 〜 import 〜
も必要です。
Python 3.7 なら、DRYで見やすい辞書リテラルを、何のデメリットも無く使えるのです。やったね!
良かったこと・その2
今までも OrderedDict
という「順序が保持された辞書」があったのですが、
所詮は普通にclass文で定義された普通のクラスにすぎません。組み込み型ではないのです。
なので、printfデバッグの際など、不細工なものを見ることになります。
from pprint import pprint
from collections import OrderedDict
# この辞書はYAMLファイルか何かから読み込んだと思いねえ
d = OrderedDict({"name": "Alice", "age": 21, "salary": 100, "foo": 1000})
# printfデバッグしてみよう
pprint(d, width=30)
# OrderedDict([('name',
# 'Alice'),
# ('age', 21),
# ('salary', 100),
# ('foo', 1000)])
# うげげ!?
もちろん dict
なら全く問題ありません。
d = {"name": "Alice", "age": 21, "salary": 100, "foo": 1000}
# printfデバッグしてみよう
pprint(d, width=30)
# {'age': 21,
# 'foo': 1000,
# 'name': 'Alice',
# 'salary': 100}
# 見やすい!
良かったこと・その3
YAMLやJSONなどを扱うライブラリを開発している方は、こんな議論を見たことがないでしょうか?
「YAMLを読むとき、キーがファイルに書かれた順序通りになるようにできませんか?」
「Pythonのdict
は順序を保存しないので無理です」
「ならOrderedDict
を使えばいいじゃないですか」
「OrderedDict
を返して既存のクソコードが動かなくなったらどうするんですか!?」
「YAMLも順序を保存しないのが仕様である!OrderedDict
は人類の堕落につながる!!」
「じゃあ、間をとってOrderedDict
を返すordered_dict=True
というオプションを追加しましょうか」
「毎回ordered_dict=True
と書くのダルいので、デフォルト設定を上書きできませんか?」
「いいこと思いついた!dict_class
という引数で辞書のクラスを変えられるようにしよう!」
「それOrderedDict
以外に使う機会あるんですか?」
まあ、自転車置き場の議論です。メリットは少ない割に、誰かが現状を調査して、何かしらの判断を下さなければなりません。
でも、組み込みの dict
が最初から順序を保存していれば、こんな議論はそもそも不要なのです。やったね!
むすび
みなさんも、ぜひ dict
の順序保証をご活用ください。
OrderedDict
よ、今までありがとう。そしてさようなら!!