PythonでJSONを弄りたい

f:id:monozukuri-bu:20190712140150j:plain

ふっちーです。よろしくお願いします。
現在python3エンジニア認定基礎試験の資格を取得するため、日々勉強に励んでいます。
資格の参考書として使用しているPythonチュートリアルの中で、手間取ったところ書いてみます。

www.oreilly.co.jp

環境

今回はGoogle Colabolatory(Colab)を使用しました。
colab.research.google.com

実践

準備

まず、作業ディレクトリを作ります。
Colabではコマンドの先頭に!をつけることでLinuxコマンドを実行できます。

!mkdir work

辞書型データの作成

まず、Pythonで辞書型(Dict)のデータを作ります。
2種類の方法で作ってみました。

①数値をKeyにする

HutoRider = {}  
memory = ['cyclone', 'joker', 'heat', 'metal', 'luna', 'trigger', 'fang', 'xtreme', 'prizm', 'accel', 'engine', 'trial']
for index, value in enumerate(memory):  
        HutoRider[index] = value  
print(HutoRider)  
出力結果:  
{0: 'cyclone', 1: 'joker', 2: 'heat', 3: 'metal', 4: 'luna', 5: 'trigger', 6: 'fang', 7: 'xtreme', 8: 'prizm', 9: 'accel', 10: 'engine', 11: 'trial'}  

enumerate関数を使って、リストの先頭から順にインデックスを振りました。
enumerate関数は引数の要素と、そのインデックス値を同時に返してくれます。

②文字(列)をKeyにする

T2memories = {}  
AtoZ = [chr(i) for i in range(ord('A'), ord('Z')+1)] #ordでascIIコード化  
print(AtoZ)  
AtoZvalue = ['アクセル','バード', 'サイクロン', 'ダミー', 'エターナル', 'ファング', 'ジーン', 'ヒート', 'アイスエイジ', 'ジョーカー', 'キー', 'ルナ', 'メタル', 'ナスカ', 'オーシャン', 'パペティア', 'クイーン', 'ロケット', 'スカル', 'トリガー', 'ユニコーン', 'バイオレンス', 'ウェザー', 'エクストリーム', 'イエスタディ', 'ゾーン']  
for alphabet, value in zip(AtoZ, AtoZvalue):  
        T2memories[alphabet] = value  
print(T2memories)  
出力結果:
['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z']

{'A': 'アクセル', 'B': 'バード', 'C': 'サイクロン', 'D': 'ダミー', 'E': 'エターナル', 'F': 'ファング', 'G': 'ジーン', 'H': 'ヒート', 'I': 'アイスエイジ', 'J': 'ジョーカー', 'K': 'キー', 'L': 'ルナ', 'M': 'メタル', 'N': 'ナスカ', 'O': 'オーシャン', 'P': 'パペティア', 'Q': 'クイーン', 'R': 'ロケット', 'S': 'スカル', 'T': 'トリガー', 'U': 'ユニコーン', 'V': 'バイオレンス', 'W': 'ウェザー', 'X': 'エクストリーム', 'Y': 'イエスタディ', 'Z': 'ゾーン'}  

1つ目の出力結果はAtoZ、2つ目の出力結果はT2memoriesです。

AtoZはリスト内包でAからZのリストを作成しています。
以下でも同じ結果が得られます。

AtoZ=[]  
for i in range(ord('A'), ord('Z')+1):  
  AtoZ.append(chr(i))  

こちらはzip関数を使って、2つのリストの先頭から一つずつ取り出してKeyとValueにしています。
zip関数でまとめるリストは同じ長さである必要があります。

JSONファイルの作成

先ほど作った辞書型のデータを使ってjsonファイルを作ってみます。

辞書型のデータをJSON形式に変換するには、jsonモジュールのdumpメソッドを使います。
このJSONデータをファイルに書き込みたいので、書き込みモード(w)でopenしておきます。

import json  

with open('./work/RiderMemory.json', 'w') as f:  
  json.dump(HutoRider, f)  

with open('./work/T2Memories.json', 'w') as f:
  json.dump(T2memories, f)

これでJSONファイルが2つ出来ました。結構あっさりですね。

中身の確認

きちんとファイルに書き込めているでしょうか。
ファイルを開いて確認してみます。

f = open('./work/RiderMemory.json','r')  

Riderdir = json.load(f)  
print(Riderdir)  
出力結果:
{'0': 'cyclone', '1': 'joker', '2': 'heat', '3': 'metal', '4': 'luna', '5': 'trigger', '6': 'fang', '7': 'xtreme', '8': 'prizm', '9': 'accel', '10': 'engine', '11': 'trial'}  

大丈夫そうで・・・あれ?
ファイルに書き込む前の辞書型データをもう一度見てみましょう。

たしか、こんな感じでした。

{0: 'cyclone', 1: 'joker', 2: 'heat', 3: 'metal', 4: 'luna', 5: 'trigger', 6: 'fang', 7: 'xtreme', 8: 'prizm', 9: 'accel', 10: 'engine', 11: 'trial'}    

JSON形式に変換したデータは、キーの数字がシングルクォートで囲まれています!

これは、Pythonではキーに文字列以外の値(今回は数値)を使えますが、JSONでは文字列に限定されているためです。
辞書型のデータのKeyに文字列以外が入っていると、JSONに変換した際に文字列に変換されます。

もう少し見やすくしたい

ところで、普通に出力すると見にくいですね・・・。
折角なので、もう少し見やすくしてみましょう。

RiderStr = json.dumps(Riderdir, indent = 4)  
print(RiderStr)   
出力結果:  
{  
    "0": "cyclone",  
    "1": "joker",  
    "2": "heat",  
    "3": "metal",  
    "4": "luna",  
    "5": "trigger",  
    "6": "fang",  
    "7": "xtreme",  
    "8": "prizm",  
    "9": "accel",  
    "10": "engine",  
    "11": "trial"  
}  

Key:Valueの単位で改行が入り、見やすくなりましたね。
json.dumps()で文字列化した際にindent=4とすることで、空白スペース4つ分のインデントが入りました。

文字化けするとき

json.dumps()で文字化けしてしまう場合、dumpsメソッドの引数にensure_ascii=Falseを追加するとうまく動いてくれます。

T2Str = json.dumps(T2dir, ensure_ascii=False, indent = 4)
print(T2Str)
出力結果:  
{  
    "A": "アクセル",  
    "B": "バード",  
    "C": "サイクロン",  
    "D": "ダミー",  
    "E": "エターナル",  
    "F": "ファング",  
    "G": "ジーン",  
    "H": "ヒート",  
    "I": "アイスエイジ",  
    "J": "ジョーカー",  
    "K": "キー",  
    "L": "ルナ",  
    "M": "メタル",  
    "N": "ナスカ",  
    "O": "オーシャン",  
    "P": "パペティア",  
    "Q": "クイーン",  
    "R": "ロケット",  
    "S": "スカル",  
    "T": "トリガー",  
    "U": "ユニコーン",  
    "V": "バイオレンス",  
    "W": "ウェザー",  
    "X": "エクストリーム",  
    "Y": "イエスタディ",  
    "Z": "ゾーン"  
}  

ソートする

辞書型のデータのKeyの順番を変えます。
今までの辞書型はKeyを軸に並んでいたので、Valueを軸に並び変えてみます。

RiderSort = sorted(Riderdir.items(), key=lambda x: x[1])
print(RiderSort)
出力結果:  
[('9', 'accel'), ('0', 'cyclone'), ('10', 'engine'), ('6', 'fang'), ('2', 'heat'), ('1', 'joker'), ('4', 'luna'), ('3', 'metal'), ('8', 'prizm'), ('11', 'trial'), ('5', 'trigger'), ('7', 'xtreme')]  

Valueがアルファベット順に並びました!

今回のキーはlambda式ですね。(Keyだけに)
lambda式は無名関数と呼ばれ、lambda 引数: 処理と書きます。

まとめ

今回はJSONの扱いを通して、以下の内容を学びました。
・enumerate
・zipメソッド
・リスト内包
・lambda式