対話モードでPythonを実行して辞書データ(JSON文字列)を処理してみた

2020.02.28

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

こんにちは、CX事業本部の若槻です。

AWSを利用したIoTシステムの開発で、作業の際にJSONデータを扱うことが多いため「この通常データのJSONを加工して例外データとしプログラムのテストに利用したい」「この1行のJSON文字列を整形して内容を見やすくしたい」という時がしばしばあります。

そこで今回は、そのような時にPython(対話モード)を利用してJSONデータを手元でぱぱっと処理して加工する方法を整理してみました。

基本的な使い方

まず、対話モードでPythonを実行して辞書データを扱う際の基本的な使い方を確認します。

  • 最初にPythonの対話モードを開始します。pythonコマンドを実行するとプロンプトが>>>となりpythonコードが対話式で実行可能となります。
$ python
Python 3.6.8 (default, May 24 2019, 18:27:52) 
[GCC 4.8.5 20150623 (Red Hat 4.8.5-28)] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>>
  • 辞書データを作成します。冒頭で{と書き改行すると、Pythonは辞書データの記述が開始されたと判断して入力モード(...というプロンプト)になり、データの内容やインデント(Tabなど)を記述できるようになる。辞書の末尾となる}を書き改行すると入力モードは終了します。
>>> {
...     "data": {
...         "userId": "test1",
...         "age": 28,
...         "enabled": True
...     }
... }
{'data': {'userId': 'test1', 'age': 28, 'enabled': True}}
  • 記述した辞書データを変数に代入することもできます。
>>> data = {
...     "data": {
...         "userId": "test1",
...         "age": 28,
...         "enabled": True
...     }
... }
>>> data
{'data': {'userId': 'test1', 'age': 28, 'enabled': True}}
  • 変数の型は辞書データなのでdictとなります。
>>> type(data)
<class 'dict'>
  • 辞書データなので添字により要素の値へアクセスすることができます。
>>> data['data']['age']
28

appendextendで辞書のリストを扱う

辞書データはappendextendによりリストのメンバーとして扱うこともできます。

  • appendを使うと辞書をリストに追加することができます。
>>> datas = []
>>> data = {
...     "data": {
...         "userId": "test1",
...         "age": 28,
...         "enabled": True
...     }
... }
>>> datas.append(data)
>>> datas
[{'data': {'userId': 'test1', 'age': 28, 'enabled': True}}]
>>> data2 = {
...     "data": {
...         "userId": "test2",
...         "age": None,
...         "enabled": False
...     }
... }
>>> datas.append(data2)
>>> datas
[{'data': {'userId': 'test1', 'age': 28, 'enabled': True}}, {'data': {'userId': 'test2', 'age': None, 'enabled': False}}]
  • 辞書のリストなのでデータ型はlistとなります。
>>> type(datas)
<class 'list'>
  • リストなのでメンバーに添字でアクセスすることができます。
>>> datas[0]
{'data': {'userId': 'test1', 'age': 28, 'enabled': True}}
  • extendによりリスト同士を結合することもできます。
>>> datas2 = [
...     {
...         "data": {
...             "userId": "test3",
...             "enabled": False
...         }
...     }
... ]
>>> datas
[{'data': {'userId': 'test1', 'age': 28, 'enabled': True}}, {'data': {'userId': 'test2', 'age': None, 'enabled': False}}]
>>> datas.extend(datas2)
>>> datas
[{'data': {'userId': 'test1', 'age': 28, 'enabled': True}}, {'data': {'userId': 'test2', 'age': None, 'enabled': False}}, {'data': {'userId': 'test3', 'enabled': False}}]

jsonモジュールによるデータの変換(json.dumpsjson.loads

jsonモジュールを利用することにより、辞書データのJSONシリアライズや、JSON文字列のJSONデシリアライズなど、辞書データとJSON文字列間の変換を行うことができます。

  • json.dumpsを使うと辞書データを文字列化(JSONシリアライズ)することができます。しかし、単にjson.dumps(data)とすると日本語などのダブルバイト文字はUnicode文字列で出力されてしまいます。
>>> data = {
...     "data": {
...             "userId": "てすと1",
...             "age": 28
...     }
... }
>>> import json
>>> json.dumps(data)
'{"data": {"userId": "\\u3066\\u3059\\u30681", "age": 28}}'
  • そこでjson.dumpsensure_asciiオプションにFalseを指定することにより日本語のまま出力することができます。
>>> json.dumps(data, ensure_ascii=False)
'{"data": {"userId": "てすと1", "age": 28}}'
  • さらにjson.dumpsindentオプションにインデント数を指定してprintに指定することにより、整形されたJSON文字列として辞書データを出力することができます。
>>> print(json.dumps(data, ensure_ascii=False, indent=4))
{
    "data": {
        "userId": "てすと1",
        "age": 28
    }
}
  • JSONシリアライズされたデータ(JSON文字列)の型はstrです。
>>> type(json.dumps(data))
<class 'str'>
  • JSONシリアライズされたデータ(JSON文字列)はjson.loadsにより辞書データに変換(JSONデシリアライズ)することができます。
>>> import json
>>> data = '{"data": {"userId": "test1", "age": 28, "enabled": true}}'
>>> data
'{"data": {"userId": "test1", "age": 28, "enabled": true}}'
>>> json.loads(data)
{'data': {'userId': 'test1', 'age': 28, 'enabled': True}}
>>> type(json.loads(data))
<class 'dict'>

エラーとなる不正な辞書データ

辞書データとして正しくない記述をするとPythonが解釈をできないためエラーとなります。エラーとなる例を示します。

  • 文字列であるにも関わらず"で囲われていない(userIdの値test1)場合はNameErrorとなります。
>>> {
...     "data": {
...         "userId": test1,
...         "age": 28,
...         "enabled": True
...     }
... }
Traceback (most recent call last):
  File "<stdin>", line 3, in <module>
NameError: name 'test1' is not defined
  • trueはBoolean型の値として使えないためNameErrorとなります。(TrueFalseと記述するのが正しい。)
>>> {
...     "data": {
...         "userId": "test1",
...         "age": 28,
...         "enabled": true
...     }
... }
Traceback (most recent call last):
  File "<stdin>", line 5, in <module>
NameError: name 'true' is not defined
  • NullnullはNone型の値として使えないためNameErrorとなります。(Noneと記述するのが正しい。)
>>> {
...     "data": {
...         "userId": "test1",
...         "age": Null,
...         "enabled": True
...     }
... }
Traceback (most recent call last):
  File "<stdin>", line 4, in <module>
NameError: name 'Null' is not defined
  • あるべき場所("age": 28の末尾)にカンマ,がない場合は入力途中でSyntaxErrorとなります。
>>> {
...     "data": {
...         "userId": "test1",
...         "age": 28
...         "enabled": True
  File "<stdin>", line 5
    "enabled": True
            ^
SyntaxError: invalid syntax

おわりに

今回は対話モードでPythonを実行して辞書データ(JSON文字列)を処理する方法を確認しました。

普段はPythonをコードの中でスクリプトとして記述して使うことがほとんどのため、いざ対話式で使うとなると「どう書けばいいんだっけ?」となることが多かったため、今回このような記事を書いて整理するに至りました。

以上