「辞書のデータをファイルに保存したいけど、どう書けばいいの?」
「JSONで保存したら、日本語が さくら みたいな謎の文字になった…」

プログラムで作ったデータを「次に起動したときも使いたい」と思ったら、まず候補になるのが JSON です。Web APIの返事も設定ファイルもJSONが多いので、避けては通れないですよね。

この記事では、Python標準の jsonモジュール を使って、辞書⇔JSONの変換、ファイルへの保存と読み込み、そして初心者がつまずきやすい日本語の文字化けと日時の保存エラーの対処までを、実際に動かしたコードで一緒に見ていきましょう!

対象は、リストと辞書の基本がわかる初心者の方です。インストール不要(標準ライブラリ)なので、すぐに試せますよ😊

JSONとは?Pythonの辞書とそっくりな「データの書き方」

notebook checklist
notebook checklist / Photo by Jakub Zerdzicki via Pexels

JSON(ジェイソン)は、データを文字で表すための書き方のルールです。イメージとしては、「Pythonの辞書やリストを、ほかのプログラムにも読める形で書き出したもの」です。

見た目はPythonの辞書とほぼ同じですが、細かい違いがあります。変換するときは、次の表のように置き換わります。

Python JSON
dict(辞書) object {...}
list・tuple array [...]
str string(必ずダブルクォート ")
int・float number
True / False true / false
None null

jsonモジュールで覚える関数は、基本の4つだけです。

  • json.dumps():Pythonのデータ → JSONの文字列
  • json.loads():JSONの文字列 → Pythonのデータ
  • json.dump():Pythonのデータ → JSONファイルに書き込む
  • json.load():JSONファイルから読み込む → Pythonのデータ

末尾に s が付くほうが「string(文字列)」用、と覚えると迷いません。

dumps・loadsで辞書とJSON文字列を変換する

まずは文字列との変換から試してみます。これ、実行する前に「どんな文字が出るか」予想できますか?

import json

# Pythonの辞書(ふつうのデータ)
user = {
    "name": "さくら",
    "age": 28,
    "skills": ("Python", "Excel"),  # タプル
    "is_member": True,
    "memo": None,
}

# ① 辞書 → JSON文字列(dumps)
text = json.dumps(user)
print(text)

# ② 日本語をそのまま出す+見やすく整形
text = json.dumps(user, ensure_ascii=False, indent=2)
print(text)

# ③ JSON文字列 → 辞書(loads)
data = json.loads(text)
print(type(data), data["skills"], data["is_member"], data["memo"])

実行すると、次のように表示されました。

{"name": "\u3055\u304f\u3089", "age": 28, "skills": ["Python", "Excel"], "is_member": true, "memo": null}
{
  "name": "さくら",
  "age": 28,
  "skills": [
    "Python",
    "Excel"
  ],
  "is_member": true,
  "memo": null
}
<class 'dict'> ['Python', 'Excel'] True None

ここが重要です👇

  • 何も指定しないと、日本語は さくら のようなエスケープ表記になる(壊れてはいませんが、人間には読めません)
  • ensure_ascii=False を付けると日本語がそのまま出る。indent=2 で改行とインデントが入って読みやすくなる
  • タプル ("Python", "Excel") は JSON では配列になるので、読み戻すとリスト ['Python', 'Excel'] になる
  • True → true、None → null に変わり、loads() で読み戻すと元の True・None に戻る

冒頭の「謎の文字になった」は、まさにこの ensure_ascii が原因です。日本語を扱うなら ensure_ascii=False はセットで覚えておきましょう。

dump・loadでToDoリストをファイルに保存する

次は、本題のファイル保存です。起動するたびにタスクが1つ増えていく、ミニToDoリストを作ってみます。

ポイントをまとめるとこんな感じです。

  • 保存は json.dump(データ, ファイル)、読み込みは json.load(ファイル)
  • ファイルを開くときは encoding="utf-8" を必ず指定する
  • 初回はファイルが無いので、FILE.exists() で確認して空のリストから始める
import json
from pathlib import Path

FILE = Path("todo.json")


def load_todos():
    """保存ファイルを読み込む。初回(ファイルが無い)は空のリストを返す"""
    if not FILE.exists():
        return []
    with FILE.open("r", encoding="utf-8") as f:
        return json.load(f)


def save_todos(todos):
    """リストをJSONファイルに保存する"""
    with FILE.open("w", encoding="utf-8") as f:
        json.dump(todos, f, ensure_ascii=False, indent=2)


todos = load_todos()
print(f"読み込み: {len(todos)}件")

# タスクを1つ追加して保存
todos.append({"title": f"タスク{len(todos) + 1}", "done": False})
save_todos(todos)

for i, todo in enumerate(todos, start=1):
    mark = "✅" if todo["done"] else "⬜"
    print(f"{i}. {mark} {todo['title']}")
ToDoリストを2回実行した結果(保存したタスクが読み込まれる)
ToDoリストを2回実行した結果(保存したタスクが読み込まれる)

2回続けて実行すると、1回目に保存したタスクが2回目にちゃんと読み込まれました。保存された todo.json の中身はこうなっています。

[
  {
    "title": "タスク1",
    "done": false
  },
  {
    "title": "タスク2",
    "done": false
  }
]

日本語がそのまま読めて、メモ帳で開いて直接編集することもできます。これがJSONで保存する大きなメリットです🚀

⚠️ encoding を省略しないでください。Windowsでは環境によって、open() の既定の文字コードがUTF-8以外(cp932)になります。書き込みと読み込みで文字コードが食い違うと、UnicodeDecodeError や文字化けの原因になります。encoding="utf-8" を毎回書いておけば、どの環境でも同じように動きます。

つまずきポイント:日時(datetime)はそのまま保存できない

ToDoに「作成日時」を付けたくなったとき、多くの人がここでつまずきます。JSONには日時を表す型が無いので、datetime をそのまま渡すとエラーになるんです。

import json
from datetime import datetime

log = {"event": "ログイン", "at": datetime(2026, 10, 12, 9, 0)}

# ① そのまま変換するとエラーになる
try:
    json.dumps(log, ensure_ascii=False)
except TypeError as e:
    print("エラー:", e)

# ② 保存するとき:日時を文字列(ISO形式)にしてから変換
saved = json.dumps({**log, "at": log["at"].isoformat()}, ensure_ascii=False)
print("保存:", saved)

# ③ 読み込むとき:文字列を日時に戻す
data = json.loads(saved)
at = datetime.fromisoformat(data["at"])
print("復元:", at, type(at).__name__)
datetimeの保存エラーと、文字列にして保存・復元した結果
datetimeの保存エラーと、文字列にして保存・復元した結果

実行結果を見ると、①で Object of type datetime is not JSON serializable(datetime型はJSONに変換できません)というエラーが出ています。

対処のしかたは、つまり「保存するときは文字列に、読むときは日時に戻す」です。

  • 保存:isoformat() で "2026-10-12T09:00:00" のような文字列にする
  • 読み込み:datetime.fromisoformat() で datetime 型に戻す

同じように、set(集合)や自作クラスのオブジェクトもそのままでは保存できません。「JSONにできるのは表の型だけ」と覚えておけば、エラーが出ても慌てずに済みますよ。

まとめ

  • jsonモジュールは標準ライブラリ。dumps/loads は文字列、dump/load はファイルと変換する
  • 日本語を読める形で保存するなら ensure_ascii=False、見やすくするなら indent=2
  • ファイルを開くときは encoding=”utf-8″ を必ず指定する
  • タプルはリストに、True/None は true/null に変わる
  • datetime は isoformat() で文字列にして保存し、fromisoformat() で戻す

設定ファイル・ゲームのセーブデータ・簡単なメモアプリなど、「データを次回も使いたい」場面はたくさんあります。まずはToDoリストのコードを動かして、todo.json の中身をのぞいてみてください。「むずかしそう」が「できそう」に変わるはずです。ぜひ試してみてください😊

\ 読んだら、次は自分で作ってみよう /

筆者が運営する無料の入門コース「作って学ぶPythonプログラミング入門」では、こうした基本文法を、割り勘計算機・おみくじ・数当てゲームなどを作りながら身につけます。各章末の定着ドリル(全42問)で、自分の手で書く練習まで。最初の4レッスンは登録なしで読めます。

→ 無料の入門コース(全7章52レッスン)を見てみる

📚 関連商品・おすすめ書籍

スッキリわかるPython入門 第2版 (スッキリわかる入門シリーズ)

もしも

スッキリわかるPython入門 第2版 (スッキリわかる入門シリーズ)

初心者に定番のPython入門書

Amazonで見る
徹底攻略! 電子工作&プログラミング Arduinoで学ぶ電子工作完全ガイド

もしも

徹底攻略! 電子工作&プログラミング Arduinoで学ぶ電子工作完全ガイド

電子工作とプログラミングを同時に学べる

Amazonで見る
実践Claude Code入門―現場で活用するためのAIコーディングの思考法

もしも

実践Claude Code入門―現場で活用するためのAIコーディングの思考法

AIコーディングの現場活用法を学ぶ一冊

Amazonで見る

※本記事にはアフィリエイトリンクが含まれます。

ABOUT ME
やまちゃん
これまで学生と社会人を合わせて5000人以上にプログラミング学習を指導。 ゼロからイチをわかりやすく解説する専門家として活動しており、本業ではArduinoを用いたIoT開発とロボットプログラミングが専門。 Pythonを用いたアプリ開発、ウェブアプリケーションの開発で業務の効率化をサポートしています。