5日目のゴール
5日目のテーマは
「クラスで作った商品オブジェクトを“ファイルに保存・読み込みできるようにすること” です。
ここまでであなたは、Product クラスを作り、
複数の商品オブジェクトをリストで管理し、
CRUD、検索、並び替えまでできるようになりました。
でも、今のままだと
アプリを終了した瞬間、すべてのデータは消えてしまいます。
今日はここに
商品オブジェクトを「保存できる形」に変換する
ファイル(JSON)に書き出す
ファイルから読み込んで、Product オブジェクトを復元する
という「クラス版・永続化(データを残す)」を足していきます。
なぜ「そのまま」ファイルに書けないのか
オブジェクトはメモリの中だけの存在
まず、ここをはっきりさせます。
Product オブジェクトは、Python が動いている間だけ
メモリの中に存在する「実物」です。
例えば、こんなコードがあったとします。
p = Product("p001", "ノートPC", 120000, 5)
Pythonこの p は「Product 型のオブジェクト」ですが、
これをそのままファイルに write(p) のように書くことはできません。
ファイルに書けるのは、基本的に「文字列」です。
つまり、オブジェクトを一度「文字列にできる形」に変換する必要があります。
ここで出てくるのが
「辞書に変換する」→「JSON にする」
という流れです。
Product を「辞書に変換する」メソッドを作る
to_dict という「変換専用メソッド」
オブジェクトをファイルに保存したいとき、
よく使われるパターンが
「オブジェクト → 辞書」
「辞書 → JSON」
という二段階です。
まずは、Product クラスに
「自分自身を辞書に変換するメソッド」を追加します。
class Product:
def __init__(self, product_id, name, price, stock):
self.product_id = product_id
self.name = name
self.price = price
self.stock = stock
def show_info(self):
print("=== 商品情報 ===")
print(f"ID: {self.product_id}")
print(f"名前: {self.name}")
print(f"価格: {self.price} 円")
print(f"在庫数: {self.stock}")
def to_dict(self):
return {
"product_id": self.product_id,
"name": self.name,
"price": self.price,
"stock": self.stock,
}
Pythonここで深掘りしたいポイントは三つです。
一つ目は、to_dict が「このオブジェクトの状態を、辞書として表現している」こと。
二つ目は、辞書のキーが "product_id", "name", "price", "stock" と、はっきり決まっていること。
三つ目は、「ファイルに保存するのはこの辞書」であって、「オブジェクトそのものではない」こと。
つまり、
「Product は、自分を辞書に変換する方法を知っている」
という状態になります。
辞書から Product を復元する from_dict
「逆変換」をクラス側に持たせる
今度は逆方向です。
ファイルから読み込んだ JSON は、
Python では「辞書」や「辞書のリスト」として扱われます。
そこから Product オブジェクトを作るには、
「辞書 → Product」という変換が必要です。
これも、クラス側に「やり方」を持たせてしまうときれいです。
class Product:
def __init__(self, product_id, name, price, stock):
self.product_id = product_id
self.name = name
self.price = price
self.stock = stock
def to_dict(self):
return {
"product_id": self.product_id,
"name": self.name,
"price": self.price,
"stock": self.stock,
}
@classmethod
def from_dict(cls, data):
return cls(
data["product_id"],
data["name"],
data["price"],
data["stock"],
)
Pythonここで重要なポイントを、しっかり押さえます。
@classmethod は「クラスメソッド」を定義するためのもの。from_dict(cls, data) の cls は「このメソッドが属しているクラスそのもの」を指す。return cls(...) と書くことで、「Product(…) を呼んでいる」のと同じ意味になる。
つまり、
Product.from_dict(some_dict)
と呼ぶと、その辞書から Product オブジェクトが一つ復元されます。
この「to_dict / from_dict のペア」は、
クラスでデータを扱うときの超定番パターンです。
複数の商品を「辞書のリスト」に変換する
products リストを保存用の形にする
アプリ側では、複数の商品をproducts というリストで持っていました。
products = [p1, p2, p3, ...]
Pythonこれをファイルに保存するには、
「Product オブジェクトのリスト」ではなく
「辞書のリスト」に変換する必要があります。
def products_to_list_dict(products):
return [p.to_dict() for p in products]
Pythonこの一行の中で、実はかなり大事なことをやっています。
[p.to_dict() for p in products] は「リスト内包表記」と呼ばれる書き方で、
「products の中の各 Product に対して to_dict を呼び、その結果の辞書を並べたリストを作る」
という意味になります。
イメージとしては、こうです。
Product オブジェクトのリスト
→ to_dict を通す
→ 辞書のリスト
この「変換してから保存する」という発想が、
クラスとファイルをつなぐカギになります。
辞書のリストから Product のリストに戻す
読み込み時の「復元処理」
今度は逆方向です。
ファイルから読み込んだ JSON は、
例えばこんな形の「辞書のリスト」になります。
[
{"product_id": "p001", "name": "ノートPC", "price": 120000, "stock": 5},
{"product_id": "p002", "name": "マウス", "price": 1500, "stock": 30}
]
Pythonこれを Product のリストに戻す関数を作ります。
def list_dict_to_products(data_list):
products = []
for data in data_list:
product = Product.from_dict(data)
products.append(product)
return products
Pythonここでのポイントは、
Product.from_dict(data) で「辞書から Product を一つ作っている」こと。
それを products リストに追加して、最後に返していること。
これで、
辞書のリスト
→ from_dict を通す
→ Product オブジェクトのリスト
という流れができました。
JSON ファイルに保存する
json.dump と「辞書のリスト」
ここから、いよいよファイルです。
Python には JSON を扱うための json モジュールがあります。
import json
Python商品一覧をファイルに保存する関数を作ります。
def save_products_to_file(products, filename):
data_list = products_to_list_dict(products)
try:
with open(filename, "w", encoding="utf-8") as f:
json.dump(data_list, f, ensure_ascii=False, indent=2)
print(f"商品情報をファイルに保存しました: {filename}")
except OSError as e:
print("ファイルの保存中にエラーが発生しました。")
print("詳細:", e)
Pythonここで深掘りしたいポイントは四つです。
一つ目は、products_to_list_dict で「オブジェクトのリスト → 辞書のリスト」に変換していること。
二つ目は、json.dump(data_list, f, ...) で「辞書のリストを JSON としてファイルに書き込んでいる」こと。
三つ目は、ensure_ascii=False によって日本語がそのまま読める形で保存されること。
四つ目は、indent=2 で見やすく整形された JSON になること。
つまり、
「ファイルに書いているのは JSON であり、その中身は“辞書のリスト”」
という構造です。
JSON ファイルから読み込む
json.load と「辞書のリスト → Product のリスト」
次に、保存したファイルから商品一覧を復元する関数を作ります。
def load_products_from_file(filename):
try:
with open(filename, "r", encoding="utf-8") as f:
data_list = json.load(f)
except FileNotFoundError:
print(f"{filename} が見つかりません。空の商品一覧から始めます。")
return []
except json.JSONDecodeError:
print("ファイルの内容が壊れているか、JSON ではありません。空の商品一覧から始めます。")
return []
except OSError as e:
print("ファイルの読み込み中にエラーが発生しました。空の商品一覧から始めます。")
print("詳細:", e)
return []
products = list_dict_to_products(data_list)
print(f"商品情報をファイルから読み込みました: {filename}")
return products
Pythonここでの重要ポイントは、
json.load(f) で「JSON → 辞書のリスト」に戻していること。list_dict_to_products で「辞書のリスト → Product のリスト」に変換していること。
ファイルがない・壊れている場合は、安全のために空のリスト [] を返していること。
これで、
ファイル
→ JSON
→ 辞書のリスト
→ Product のリスト
という復元の流れが完成しました。
アプリ起動時に読み込み、終了時に保存する
main の中に「永続化の流れ」を組み込む
ここまで作った関数を、アプリ全体の流れに組み込みます。
まず、ファイル名を決めておきます。
DATA_FILE = "products.json"
Pythonそして main をこう書き換えます。
def main():
products = load_products_from_file(DATA_FILE)
while True:
show_menu()
choice = input("番号を選んでください: ").strip()
if choice == "1":
add_product(products)
elif choice == "2":
show_all_products(products)
elif choice == "3":
update_product(products)
elif choice == "4":
delete_product(products)
elif choice == "5":
show_product_detail(products)
elif choice == "6":
show_low_stock_products(products)
elif choice == "7":
show_products_sorted_by_price(products)
elif choice == "8":
show_products_sorted_by_name(products)
elif choice == "9":
save_products_to_file(products, DATA_FILE)
elif choice == "0":
print("アプリを終了します。変更を保存します。")
save_products_to_file(products, DATA_FILE)
break
else:
print("不正な入力です。0〜9 のどれかを選んでください。")
Pythonここでの流れを、日本語だけで整理してみます。
アプリ起動時
「products.json があれば読み込んで Product のリストに復元し、products に入れる。
なければ空の products = [] から始める。」
アプリ利用中
「products に対して、登録・更新・削除・検索・並び替えなどを行う。」
アプリ終了時
「今の products の状態を、辞書のリスト → JSON として products.json に保存する。」
この構造が見えたら、
「オブジェクトの世界」と「ファイルの世界」が頭の中でつながっている
と言えます。
5日目のまとめ 今日つかんでほしい感覚
今日の本質は、これです。
Product オブジェクトは、そのままではファイルに書けない。
一度「辞書」に変換してから、JSON として保存する。to_dict と from_dict は、「オブジェクト ↔ 辞書」の橋渡しをするペア。
複数の商品は「Product のリスト ↔ 辞書のリスト」として変換する。
アプリ起動時に読み込み、終了時に保存することで、「前回の続きから使えるアプリ」になる。
ここまで来たあなたは、
「クラスで作ったオブジェクトを、ファイルに残してまた復元する」
という、かなり実践的なスキルを手に入れています。
6日目・7日目では、
この商品管理アプリ全体をクラスとしてまとめたり、
コードの構造を自分の言葉で説明できるレベルまで整理していきます。


