1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

Python(Django) x Docker x AWSAdvent Calendar 2023

Day 23

【Python】jsonモジュールでエンコード・デコードするときの注意点2つ

Posted at

概要

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

最後に、エンコード・デコード時のNonenullについて。
以下のコードを叩いてみます。

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を扱う際には要注意ポイントですね。

1
0
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
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?