web-dev-qa-db-ja.com

json.dumpsを使用すると、python dictのintキーが文字列に変わるのはなぜですか?

この変換テーブル 、Python intsはJSONモジュールを使用してシリアル化されるとJSON番号として書き込まれます。

私は整数キーと整数値を持つ辞書を持っています:

>>> d = {1:2}
>>> type(d.items()[0][0])
<type 'int'>
>>> type(d.items()[0][1])
<type 'int'>

Jsonモジュールを使用してこれをJSON文字列にシリアル化すると、値は数値として書き込まれますが、キーは文字列として書き込まれます。

>>> json.dumps(d)
'{"1": 2}'

これは私が望んでいる動作ではなく、json.dumps/json.loadsのラウンドトリップを破壊するため、特に壊れているようです。

>>> d == json.loads(json.dumps(d))
False

なぜこれが起こるのですか?キーを数字として強制的に書き込む方法はありますか?

29
jveldridge

単純な理由は、 JSONは整数キーを許可しません。

object
    {}
    { members } 
members
    pair
    pair , members
pair
    string : value  # Keys *must* be strings.

この制限を回避する方法については、まず、受信側の実装が技術的に無効なJSONを処理できることを確認する必要があります。次に、すべての引用符を置き換えるか、カスタムシリアライザーを使用します。

35
Sean Vieira

この関数は、可能であれば、すべての文字列キーをintキーに再帰的にキャストします。不可能な場合、キータイプは変更されません。

JLT's 以下の例を少し調整しました。私の巨大なネストされた辞書のいくつかで、コードは辞書のサイズを変更し、例外で終了しました。とにかく、クレジットはJLTにあります!

def pythonify(json_data):

    correctedDict = {}

    for key, value in json_data.items():
        if isinstance(value, list):
            value = [pythonify(item) if isinstance(item, dict) else item for item in value]
        Elif isinstance(value, dict):
            value = pythonify(value)
        try:
            key = int(key)
        except Exception as ex:
            pass
        correctedDict[key] = value

    return correctedDict
0
Jonas Melin

本当にしたい場合は、キーをもう一度整数に変換できるかどうかを確認することができます:

def pythonify(json_data):
    for key, value in json_data.iteritems():
        if isinstance(value, list):
            value = [ pythonify(item) if isinstance(item, dict) else item for item in value ]
        Elif isinstance(value, dict):
            value = pythonify(value)
        try:
            newkey = int(key)
            del json_data[key]
            key = newkey
        except TypeError:
            pass
        json_data[key] = value
    return json_data
0
JLT