よちよちpython

独習 python/Qpython/Pydroid3/termux/Linux

13日の金曜日

本日は2019年9月13日の金曜日でございます。
今回はそれに因んでPythonでのJsonファイルをいじってみる。

目次


Jsonとは?


「ジェイソン」とは?
コイツだ。

f:id:chayarokurokuro:20190914020313j:plain


チェーンソーなど振り回して危ねぇ奴。


違う? じゃあ、こやつか。

f:id:chayarokurokuro:20190914020339j:plain


記憶をなくしたCIA工作員。コイツも危ねぇ。

これも違うっぽい。
Wikipediaには以下のように書いてある。

JavaScript ObjectNotation

JSON、ジェイソン)は軽量なデータ記述言語の1つである。構文はJavaScriptにおけるオブジェクトの表記法をベースとしているが、JSONJavaScript専用のデータ形式では決してなく、様々なソフトウェアやプログラミング言語間におけるデータの受け渡しに使えるよう設計されている。

(中略)

MIMEタイプは application/json、拡張子はjsonとされた。   ウィキペディア json

データの記述方式の一つだとか。 JavaScriptが何とかかんとかと書いてあるが、何のプログラミング言語でも、もちろんPythonでも扱うことができる。 高速で処理でき、人が扱い易い構造をしていて便利。   ファイルの拡張子はjson

プログラミングをしない人がこの形式のファイルを扱う事はまずないと思う。

2018年6月6日東洋経済新報社掲載の記事 一瞬話題になったこの記事。日々、統計を読み経済誌に文章を書く人でさえ、あまり扱わないらしい。

Jsonってどんな形式?

早く言えば、Pythonの入門の最初の方にでてくる辞書型の配列。 辞書型のデータが書き込まれたファイルと思ってよさそうです。


辞書型はこんなのでした。

{key1:value1, key2:value2}  

keyvalueが対になって:で結ばれている。
そして各々が,で区切られ連なっている。


誰かのテストの点数を教科別で書き表すならこんな感じ。

{"国語": 88, "算数": 74, "理科": 72, "社会": 65, "英語": 79}  


辞書の中に辞書やリストを入れたりして、もうちょっと多くの情報を表すこともできる。

{   
"関羽":{
        "統率力": 86,
        "武力"  : 95, 
        "知力"  : 85,
        "交渉力" : 73,
        "教養力" : 84
       },
"張飛":{
        "統率力": 72,
        "武力"  : 98, 
        "知力"  : 38,
        "交渉力" : 42,
        "教養力" : 50
       }
}

jsonファイルはこんな感じの辞書型データになっている。(※ データの数字は適当です。)



Jsonはどこで使われてる?

普段はほとんど見かけませんね。統計データだとか検索しても拡張子がcsvxlsxxmlのファイルばかりですが、データベースやWebアプリケーションでは使われることが多いのだとか。


ライブドアの天気APIや、TwitterAPIなどを使うならJsonに出会います。🎭




おさらい 辞書型の読み取り


ところで、辞書型の読み取りってどうするんだっけ?
簡単に復習します。

# 辞書型のデータ
data = {"国語": 88, "算数": 74, "理科": 72, "社会": 65, "英語": 79} 

# dataを出力
print("\n・「data」\n",data)

# タイプは
print("\n・「タイプ」\n",type(data))

# keyのリストを取り出す
key_lst = data.keys()
print("\n・『keyのリスト』\n",key_lst)

# valueのリストを取り出す
value_lst = data.values()
print("\n・『valueのリスト』\n",value_lst)

# keyとvalueをitems()で一行ずつ取り出す
for k,v in data.items():
    print("\n・《 keyとvalue 》\n",k,v)

# keyを指定して国語のデータだけを取得
print("\n・【国語】\n",data["国語"])

# 同様に、key指定で英語のデータを取得
print("\n・【英語】\n",data["英語"])
・「data」
 {'国語': 88, '算数': 74, '理科': 72, '社会': 65, '英語': 79}

・「タイプ」
 <class 'dict'>

・『keyのリスト』
 dict_keys(['国語', '算数', '理科', '社会', '英語'])

・『valueのリスト』
 dict_values([88, 74, 72, 65, 79])

・《 keyとvalue 》
 国語 88

・《 keyとvalue 》
 算数 74

・《 keyとvalue 》
 理科 72

・《 keyとvalue 》
 社会 65

・《 keyとvalue 》
 英語 79

・【国語】
 88

・【英語】
 79



Jsonファイルの読み書き


ここからは実際にJsonファイルの読み書きを行って行きます。

jsonを扱うときは、次の表にある関数を使います。

関数 使い方
json.load() jsonファイルを辞書として読む
json.loads() json文字列を辞書型に変換
json.dump() 辞書型をjsonファイルで保存
json.dumps() 辞書型をjson文字列に変換


似ているので間違い易い。

文字列として扱うかどうか で関数の最後に s が付いたり付かなかったりしている。

  • jsonファイルを辞書として読むときは、json.load()
  • jsonファイルに辞書を保存するときは、json.dump()

辞書として読み書きしないと、keyvalueで値を取り出したりが出来ないということですかね。

json文字列とは、{}で囲まれて辞書型を装っているが、実は単なる文字列。

  • json文字列を辞書に変換するときはjson.loads()
  • 辞書をjson文字列に変換するときはjson.dumps()



辞書型をわざわざ文字列に変換したい時とはどんな状況だろうか?
テキストとして文章中で使ったり?



Pythonのコードを書く上でjsonを扱うときはJsonモジュールが必要ですが、Python標準モジュールなのでインストールする必要はありません。

import json  


通常のファイルのように、open()関数でmodeで"r"や"w"などを指定して開きます。

そして、上の表の関数で読み書きを行う。



Jsonファイルに書く


違いがよくわからんので、実際にjsonファイルに書き出します。
ファイルに書くときはjson.dump()を使います。

jsonファイルを新規作成します。

import json

# 作成するファイル名
file1_name = "test1_json_dump.json"


# 辞書型データを用意
data = {"投稿日":"20190913","ユーザー名":"名無しさん","内容":"オマエモナー"}

################################
# データのタイプ
print(type(data))

# wモードで開いてjson.dump()で書き込む
with open(file1_name,"w") as f:
    json.dump(data,f)
<class 'dict'>

データのタイプはdictでした。
json.dump()でファイルに保存しましたので、スマホアプリのJota+で開いてみます。(読み込み時自動検出)


[f:id:chayarokurokuro:20190914020521j:plain]

日本語部分が「u\数字」に置き換わってますねぇ。
一旦これを無視して、作ったファイルを読み込んでみます。



jsonファイルを辞書として読む


json.load()を使います。

import json

file1_name = "test1_json_dump.json"

with open(file1_name,"r") as f:
    r = json.load(f)
    print(type(r))
    print("***************")
    print(r)
<class 'dict'>
***************
{'投稿日': '20190913', 'ユーザー名': '名無しさん', '内容': 'オマエモナー'}

あら?今度はちゃんと表示されました。「\u数字」は何処いった?

タイプはdictです。

note.nkmk.me PythonでJSONファイル・文字列の読み込み・書き込みによると、

文字列の \u数字Unicodeエスケープシーケンス
JSONでは全角文字などの非ASCII文字がUnicodeエスケープされている場合がある。


「場合がある」…
さらに

json.loads()とjson.load()では、特になにも設定しなくてもUnicodeエスケープシーケンスが対応する文字列に変換される。


確かに、Unicodeエスケープシーケンスが対応文字列に変換されて読まれました。



辞書を文字列に変換し書き込む


Unicodeエスケープシーケンスからエスケープし、次に進む。

今度はjson.dumps()で辞書を文字列に変換してjson.dump()で書き込んでみる。

# 辞書型データを用意
data = {"投稿日":"20190913","ユーザー名":"名無しさん","内容":"オマエモナー"}

################################
# データのタイプ
print(type(data))
print("***************")

# データをjson.dumps()で文字列に変換
data2 = json.dumps(data)

# 変換したデータのタイプ
print(type(data2))
print("***************")

# ファイルを新規作成
file2_name = "test2_json_dump.json"

# 文字列をjson.dump()で書き込む
with open(file2_name,"w") as f:
    json.dump(data2,f)
<class 'dict'>
***************
<class 'str'>
***************

データがdict型からstr型に変わっています。

作成されたファイルをメモ帳アプリJota+でみます。

[f:id:chayarokurokuro:20190914020546j:plain]


全体の前後に"が付いて文字列になっている。バックスラッシュも更に付いた。

文字列なのに、何故かjson.dump()で書き込めた。

json.load()で読み込んでみる。
無理やろこれは…

with open(file2_name,"r") as f:
    r2 = json.load(f)
    print(type(r2))
    print("***************")
    print(r2)
<class 'str'>
***************
{"\u6295\u7a3f\u65e5": "20190913", "\u30e6\u30fc\u30b6\u30fc\u540d": "\u540d\u7121\u3057\u3055\u3093", "\u5185\u5bb9": "\u30aa\u30de\u30a8\u30e2\u30ca\u30fc"}

あら?エラーなしで読み込めた。
全体がstr型の文字列。
Unicodeエスケープシーケンスのまんま。

文字列なので、辞書として機能しない筈。一応確める。

# items()でキーとバリュー取得の無駄な試み

r2.items()
AttributeErrorTraceback (most recent call last)

<ipython-input-26-0e11ea6d69e5> in <module>()
      1 # items()でキーとバリュー取得の無駄な試み
      2 
----> 3 r2.items()


AttributeError: 'str' object has no attribute 'items'

エラーでました。
AttributeError 文字型のオブジェクトはitemsの属性を持たないよと。

この辞書型に扮する文字列を、json.loads()を使えば辞書にできるのか?



文字列を辞書に変換する


json.loads()を使えばできる筈。

# 文字列を辞書に変換 r2は上で取得した文字列
r3 = json.loads(r2)

# 変換後のタイプ
print(type(r3))
print("***************")

# 変換後の中身
print(r3)
<class 'dict'>
***************
{'投稿日': '20190913', 'ユーザー名': '名無しさん', '内容': 'オマエモナー'}

おお!
辞書型に変換され、読める文字列に直った。

あと数分で13日の金曜日が終わるので、ここまで!