[Python] キャメルケースの辞書キーをスネークケースに変換する

こんにちは。サービスグループの武田です。Pythonの辞書で、キャメルケースのキーをスネークケースに変換する方法を考えてみました。
2021.06.18

こんにちは。サービスグループの武田です。

識別子の命名規則は普段どんなものを使っていますか?主なものとしては次の4種類が挙げられます。

  • アッパーキャメルケース(パスカルケース)
  • ローワーキャメルケース(単にキャメルケース)
  • スネークケース
  • ケバブケース(チェインケース)

使用するプログラミング言語などによって、採用率は異なるのが一般的です。たとえばJavaであればクラス名はアッパーキャメルケースで、メソッド名や変数名はローワーキャメルケース。Pythonであればクラス名はアッパーキャメルケースで変数名などはスネークケース、などが多い認識です(プロジェクトによってはこの限りではありません)。

それではJSONはどうでしょう。JSONはREST APIなどに代表されるデータ交換用のフォーマットのひとつで、軽量なテキストベースということもあり広く普及しています。JSONにはキーと値をペアとした、いわゆるマップとか連想配列や辞書などと呼ばれるデータ型が扱えます。キーは文字列なのですが、前述した命名規則がサービスによって割とバラバラだったりします。

軽く調べてみたところ、GitHubやFacebookなどはスネークケース。AWSやGoogle Cloudなどはキャメルケースでした。さてここで問題になったのが、Web APIのレスポンスデータ(JSON)をPythonで扱う際にキーの命名規則がずれてしまうことでした。Pythonで辞書型のデータを扱う際、普段はキーをスネークケースで扱っているのに、レスポンスデータはキャメルケースになってしまうのです。データのスコープがとても狭いのであればそこだけ注意すればいいのですが、たらい回しにするケースだと至るところで違いを意識する必要が出てしまい、ノイズになってしまいます。

そんなわけで簡単な変換用の関数を用意して解決してみました。

検証環境

おそらく古過ぎなければたいてい動くはずです。今回はこちら。

$ python3 -V
Python 3.7.9

関数および動作確認

関数は次のようなものを定義しました。変換部分は別関数に切り出すことで、他の変換にも対応できるようにしています。

import re
from typing import Any, Callable


def camel_to_snake(s: str) -> str:
    return re.sub("((?<=[a-z0-9])[A-Z]|(?!^)[A-Z](?=[a-z]))", r"_\1", s).lower()


def convert_dict_key(d: dict, conv: Callable[[str], str]) -> dict:
    def convert_value(v: Any) -> Any:
        return (
            convert_dict_key(v, conv)
            if isinstance(v, dict)
            else [convert_value(e) for e in v]
            if isinstance(v, list)
            else v
        )

    return {conv(k): convert_value(v) for k, v in d.items()}

それでは実際に試してみます。

>>> convert_dict_key({"yourName":"mitsuha"}, camel_to_snake)
{'your_name': 'mitsuha'}
>>>
>>> convert_dict_key({"HEROINE":{"yourName":"mitsuha"}}, camel_to_snake)
{'heroine': {'your_name': 'mitsuha'}}
>>>
>>> convert_dict_key({"characters":[{"yourName":"taki"},{"yourName":"mitsuha"}]}, camel_to_snake)
{'characters': [{'your_name': 'taki'}, {'your_name': 'mitsuha'}]}

大丈夫そうです!

まとめ

辞書のキーについては、「そういうものだ」と受け入れられれば済む問題ではありますが、コードの一貫性の観点から統一したいケースもあります。そういうときに思い出してもらえれば幸いです。

参考サイト