🐍 Python
Python型とJSON型の対応関係
JSONの型はPythonの型よりも種類が少ないため、変換の過程で「情報が失われる」「別の型に丸められる」ことがあります。特に辞書のキーとタプルの扱いは見落としやすいポイントです。
tuple → JSONの配列(list)になる(往復するとtupleではなくlistで返る)
辞書のキー(int/None/bool) → JSONでは文字列キーに変換される
# タプルは配列になり、往復するとlistに変わる
import json
data = {"tup": (1, 2, 3)}
s = json.dumps(data)
print(s)
# {"tup": [1, 2, 3]}
back = json.loads(s)
print(type(back["tup"]))
#
# 辞書のキーが文字列以外だと、JSONでは文字列に変換される
import json
print(json.dumps({1: "int key"}))
# {"1": "int key"}
print(json.dumps({None: "none key"}))
# {"null": "none key"}
print(json.dumps({True: "true key"}))
# {"true": "true key"}
# 【JSONとは別の注意点】Pythonの辞書リテラルで1とTrueを両方キーに使うと、
# True == 1 かつ hash(True) == hash(1) であるため、後に書いた方の値で上書きされて1つのキーに潰れる
d = {1: "a", True: "b"}
print(d)
# {1: 'b'}
print(len(d))
# 1
主な型対応表
- dict → object({})
- キーは文字列化される。int/float/bool/Noneのキーはそれぞれ"1"、"1.5"、"true"/"false"、"null"のような文字列になる
- list / tuple → array([])
- どちらもJSONでは同じ配列になる。
tupleで保存しても読み込むとlistになり、元の型情報は失われる - str/int/float/bool/None → 対応するJSON型
- ほぼそのまま対応するが、非常に大きい整数やNaN/Infinityは別ページで解説する注意点がある
💡 AIコードレビュー観点:往復させると元の型に戻らないことがある
AIが生成したコードで「タプルで持っていたデータをJSON経由で保存し、読み込んでからタプルのメソッドやタプル前提の処理(アンパック以外の型チェック等)を行う」設計になっている場合、読み込んだ値は実際にはlistであるためisinstance(x, tuple)のようなチェックがFalseになる可能性があります。同様に、辞書のキーに整数を使うつもりでjson.loads()後の辞書に整数でアクセスしようとすると、実際のキーは文字列"1"になっているためKeyErrorになります。JSONを経由するデータは「型が保証されない」という前提で扱いましょう。