LoginSignup
2
3

More than 5 years have passed since last update.

pythonでjsonの型を動的に読み込む

Last updated at Posted at 2016-04-23

pythonではjsonモジュールはパッケージ同梱ですが、yamlモジュールはサードパーティ製です。
現在作成しているプログラムでは、環境の違いを吸収するため

  1. もしyamlモジュールがあり、yamlのconfigファイルがあればそれを読む。
  2. ダメならjsonでの読み込みを試みる。
  3. それでもだめなら例外を挙げる

という挙動を採用しています。
yamlとjsonは似たインターフェイスを持っているので、以下のように全く同じように扱ったのですが、

try:
    import yaml
    with open("config.yaml") as y:
        config = yaml.load("config.yaml")
except ImportError:
    import json
    try:
        with open("config.json") as j:
            config = json.load(j)
    except AttributeError:
        logger.error("please set config file in json or yaml !!")
        raise


# 以下でconfigの値を使用する… 

ここに落とし穴がありました。
yamlの場合、keyの型を自動的に推測して読み込んでくれるのですが、jsonは必ずstrにします。
つまりコンフィグファイルが以下のような内容だった場合

config.yaml
1: "hoge"
key: "fuga" 
config.json
{
    "1": "hoge",
    "key": "fuga"
}

いずれの場合もconfig["key"]"fuga"にアクセスできますが、"hoge"の方はjsonならばconfig["1"], yamlならばconfig[1]でアクセスしなくてはなりません。

これを避けるにはjson.load()時にフックとして関数を与えます。

def jsonkeys_to_int_always(x): # keyの型をすべてintにできるときはこちらでOK
    if isinstance(x, dict):
            return {int(k):v for k,v in x.items()}
    return x

def jsonkey_to_int_when_possible(x): # yamlと同様の挙動をさせたいときはこちら
    d = {}
    if isinstance(x, dict):
        for k,v in x.items():
            try:
                k = int(k)
            except ValueError:
                pass
            d[k] = v
        return d

config = json.load("config.json", object_hook=jsonkeys_to_int_when_possible)

yamlの中で値を指定することで、違いを吸収することもできる様ですが、詳しくは知りません。

2
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
3