概要
Pythonのjson.dumps()とjson.loads()について、注意点を2点整理してみました。
以下のコードをサンプルとして進めます。
import json
#1
data = {}
data['sample_id'] = 'test'
sample_id = json.dumps(data['sample_id'])
print(data)
print(sample_id)
#2
data = {}
data['sample_id'] = 'test'
sample_id = data['sample_id']
print(data)
print(sample_id)
こちらを実行すると結果は以下の通り。
{'sample_id': 'test'}
"test"
{'sample_id': 'test'}
test
あれ、#1では"test"というようにダブルクオーテーションで囲まれているのに対して、#2ではtestというようにダブルクオーテーションがありません。
テストコードを書いているときに、プログラム側となぜか結果が異なるなぁ...と思っていたら理由はjson.dumpsにありました。
注意点1:JSON形式にエンコードしているかどうかで変わる
#1では、JSON形式の文字列に変換(=エンコード)しているのでダブルクォーテーションで囲まれた文字列が出力されます。(これはデフォルトの挙動。なぜ?というと...JSONの仕様がJavaScriptのオブジェクト表記を採用しているからでしょう)
一方、#2では、単純に文字列を別の変数にコピーしているので、ダブルクォーテーションは付与されません。
json.loads()でデコードするときに影響が出る
これがどんな点に影響が出るのか?というと、json.loads()を使ってPythonのデータ構造に変換するとき、つまり辞書型に戻す(=デコード)するときです。
json.loads()は、渡された文字列が JSON 形式でない場合にエラーが出るので、たとえば以下のコードで実行すると#2の一番最後のprint文でエラーになります。
import json
#1
data = {}
data["sample_id"] = "test"
sample_id = json.dumps(data["sample_id"])
print(data)
print(sample_id)
test = json.loads(sample_id)
print(test)
#2
data = {}
data["sample_id"] = "test"
sample_id = data["sample_id"]
print(data)
print(sample_id)
test = json.loads(sample_id)
print(test)
実行結果は以下の通り。
{'sample_id': 'test'}
"test"
test
{'sample_id': 'test'}
test
Traceback (most recent call last):
##略##
raise JSONDecodeError("Expecting value", s, err.value) from None
json.decoder.JSONDecodeError: Expecting value: line 1 column 1 (char 0)
上述の通り、json.dumpsを使っていない場合は単なる文字列なので、JSONDecodeErrorになります。
文字通り、デコードに失敗したエラー、ということがわかりますね。
dataは結果も型も同じように出力されますが、エンコード・デコードの処理が入るのでJSON形式であるかどうかが大事になります。テストコードとか書くときなどはprint結果だけ見ていると要注意だなと思いました。
注意点2:Noneとnull
最後に、エンコード・デコード時のNoneとnullについて。
以下のコードを叩いてみます。
import json
dict_data = {"samples": {"key1": "value1", "key2": "value2", "key3": None}}
json_data = json.dumps(dict_data)
print(json_data)
dict_data = json.loads(json_data)
print(dict_data)
結果は以下。
{"samples": {"key1": "value1", "key2": "value2", "key3": null}}
{'samples': {'key1': 'value1', 'key2': 'value2', 'key3': None}}
json.dumps()関数は、JSON形式の文字列に変換するとき、PythonのNone値はJSONのnullとしてシリアライズされます。逆に、json.loads()関数は、Pythonオブジェクトに戻すとき、PythonのNoneに変換されます。
ここもPythonでjsonを扱う際には要注意ポイントですね。