基礎から学ぶPython入門 90日コース | 実践開発 - Day 86:基本機能を実装

Python 90日で身につけるPython
スポンサーリンク
スポンサーリンク

Day 86:基本機能を実装 ― 「まずは“動く一本の線”を通す」

Day 86では、いよいよ最終プロジェクトの 基本機能を実装 していきます。

テーマはとてもシンプルで、でも本質的です。

入力 ↓ データ処理 ↓ 保存

この「一本の流れ」を、まずは確実に通します。 細かい機能や見た目は、あとからいくらでも育てられます。 最初にやるべきことは、

「データがちゃんと入って、処理されて、保存される」

この“動く一本の線”を作ることです。

ここでは、前回までの「売上管理・分析システム」を例に、 CSV → データチェック → SQLite保存 という流れを、ステップバイステップで組み立てていきます。

全体の流れをもう一度イメージする

まずは、今日作る「一本の線」を、言葉で整理してみます。

  1. ユーザーが売上CSVをシステムに渡す(入力)
  2. システムがCSVを読み込み、データをチェックする(データ処理)
  3. チェック済みデータをSQLiteに保存する(保存)

この3ステップが完成すると、

  • 「とりあえずデータは入る」
  • 「壊れたデータは弾かれる」
  • 「あとから集計やレポートが作れる」

という状態になります。

では、ひとつずつコードにしていきましょう。

入力 ― 「まずはCSVを受け取れるようにする」

シンプルなスタート:ファイルパスを受け取る関数

最初からWeb APIにしてもいいのですが、 ここでは 「まずはシンプルに、ローカルのCSVファイルを読む」 ところから始めます。

# services/csv_input.py
import csv
from typing import Any

def read_csv(path: str) -> list[dict[str, Any]]:
    """
    CSVファイルを読み込み、1行ごとに辞書として返します。

    path: 読み込みたいCSVファイルのパス
    戻り値: 各行を辞書にしたリスト
    """
    rows: list[dict[str, Any]] = []

    # ファイルを開く
    with open(path, encoding="utf-8") as f:
        reader = csv.DictReader(f)

        # 1行ずつ読み込んでリストに追加
        for row in reader:
            rows.append(row)

    return rows
Python

ここでやっていることは、とても素直です。

  • csv.DictReader を使って、ヘッダー行をキーにした辞書として読む
  • 各行を rows リストに追加していく
  • 最終的に「行のリスト」を返す

ポイント:

「まずは、データが“入ってくる”ところを作る」 ここではまだ、チェックも保存もしていません。 入力だけに集中します。

データ処理 ― 「壊れていないかを確認し、型を整える」

次に、読み込んだデータを 処理(チェック+整形) します。

売上データのバリデーションと整形

# services/sales_processing.py
from typing import Any
from models.sale import Sale

def validate_and_convert(rows: list[dict[str, Any]]) -> list[Sale]:
    """
    CSVから読み込んだ行データをチェックし、
    Saleモデルのリストに変換します。

    - 必須項目が空でないか
    - 金額が整数として扱えるか
    などを確認します。
    """
    sales: list[Sale] = []

    for row in rows:
        # 必須項目チェック
        if not row.get("date"):
            raise ValueError("date が空です")
        if not row.get("item"):
            raise ValueError("item が空です")
        if not row.get("amount"):
            raise ValueError("amount が空です")

        # 金額を整数に変換
        try:
            amount_int = int(row["amount"])
        except ValueError:
            raise ValueError(f"amount が整数ではありません: {row['amount']}")

        # Saleモデルに変換
        sale = Sale(
            id=None,                 # まだDBに保存していないので None
            date=row["date"],
            item=row["item"],
            amount=amount_int,
            customer_id=None,        # 今回は顧客情報なしでスタート
        )

        sales.append(sale)

    return sales
Python

ここでの大事なポイントは3つです。

  1. 必須項目のチェック
    • date / item / amount が空ならエラー
  2. 型の整形
    • amount を int に変換しておく
  3. モデルへの変換
    • 生の辞書ではなく、Sale クラスにしておく

「生のデータを、そのままシステムに流さない」 これが、セキュリティと品質の両方の面で、とても大事な考え方です。

保存 ― 「チェック済みデータをSQLiteに蓄える」

最後に、整形済みの Sale を SQLiteに保存 します。

売上保存用のリポジトリ

# repositories/sales_repository.py
import sqlite3
from models.sale import Sale

DB_PATH = "sales.db"

def save_sales(sales: list[Sale]) -> None:
    """
    SaleモデルのリストをSQLiteに保存します。
    """
    conn = sqlite3.connect(DB_PATH)
    cur = conn.cursor()

    for sale in sales:
        cur.execute(
            """
            INSERT INTO sales (date, item, amount, customer_id)
            VALUES (?, ?, ?, ?)
            """,
            (sale.date, sale.item, sale.amount, sale.customer_id),
        )

    conn.commit()
    conn.close()
Python

ポイント:

  • リポジトリ層は「DBとの会話だけ」に集中する
  • Sale モデルを受け取り、カラムに対応させてINSERTする
  • コミットとクローズを忘れない

3つをつなぐ「メインの一本の線」を作る

ここまでで、

  • 入力:read_csv
  • データ処理:validate_and_convert
  • 保存:save_sales

という3つの部品ができました。

これを ひとつの流れ としてつなぐのが、 Day 86のクライマックスです。

# main.py
from services.csv_input import read_csv
from services.sales_processing import validate_and_convert
from repositories.sales_repository import save_sales
from repositories.schema import create_tables  # テーブル作成用

def main() -> None:
    """
    基本機能のメイン処理。
    入力 → データ処理 → 保存 の一本の線を通します。
    """
    # 1. テーブルがなければ作成
    create_tables()

    # 2. CSVを読み込む(入力)
    rows = read_csv("sales_sample.csv")
    print(f"読み込んだ行数: {len(rows)}")

    # 3. データチェック&整形(データ処理)
    sales = validate_and_convert(rows)
    print(f"有効な売上データ件数: {len(sales)}")

    # 4. SQLiteに保存(保存)
    save_sales(sales)
    print("売上データを保存しました")


if __name__ == "__main__":
    main()
Python

この main() が、 今日のテーマである 「最重要機能の一本の線」 です。

重要な“設計の感覚”をもう一度整理する

Day 86で、みなさんが掴んでほしい感覚は、 単に「コードが動いた」ということだけではありません。

それ以上に大事なのは、次の3つです。

1. 入力・処理・保存を分ける

  • 入力:ファイルやAPIからデータを受け取る
  • 処理:チェック・整形・変換を行う
  • 保存:データベースに蓄える

この3つを 別々の関数・モジュール に分けることで、

  • 変更しやすくなる
  • テストしやすくなる
  • バグの原因を特定しやすくなる

というメリットが生まれます。

2. 生データをそのまま信じない

CSVや外部入力は、 必ずしも「きれいなデータ」とは限りません。

  • 空欄
  • 型違い
  • 想定外の値

こうしたものを、 処理の前にちゃんとチェックする ことで、

「システムの中に“汚れ”を持ち込まない」

という状態を作れます。

3. モデル(クラス)を通して扱う

辞書や生の行データではなく、 Sale のような モデルクラス を通して扱うことで、

  • 型ヒントが効く
  • 意図がコードに残る
  • ツール(mypyなど)がチェックしてくれる

という、コード品質の面でのメリットも得られます。

Day 86ミニテンプレート ― そのまま使える「基本機能セット」

最後に、今日の内容を ひとまとめのテンプレートとして並べておきます。

1. 入力

# services/csv_input.py
import csv
from typing import Any

def read_csv(path: str) -> list[dict[str, Any]]:
    """
    CSVファイルを読み込み、1行ごとに辞書として返します。
    """
    rows: list[dict[str, Any]] = []
    with open(path, encoding="utf-8") as f:
        reader = csv.DictReader(f)
        for row in reader:
            rows.append(row)
    return rows
Python

2. データ処理

# services/sales_processing.py
from typing import Any
from models.sale import Sale

def validate_and_convert(rows: list[dict[str, Any]]) -> list[Sale]:
    """
    CSVから読み込んだ行データをチェックし、
    Saleモデルのリストに変換します。
    """
    sales: list[Sale] = []

    for row in rows:
        if not row.get("date"):
            raise ValueError("date が空です")
        if not row.get("item"):
            raise ValueError("item が空です")
        if not row.get("amount"):
            raise ValueError("amount が空です")

        try:
            amount_int = int(row["amount"])
        except ValueError:
            raise ValueError(f"amount が整数ではありません: {row['amount']}")

        sale = Sale(
            id=None,
            date=row["date"],
            item=row["item"],
            amount=amount_int,
            customer_id=None,
        )
        sales.append(sale)

    return sales
Python

3. 保存

# repositories/sales_repository.py
import sqlite3
from models.sale import Sale

DB_PATH = "sales.db"

def save_sales(sales: list[Sale]) -> None:
    """
    SaleモデルのリストをSQLiteに保存します。
    """
    conn = sqlite3.connect(DB_PATH)
    cur = conn.cursor()

    for sale in sales:
        cur.execute(
            """
            INSERT INTO sales (date, item, amount, customer_id)
            VALUES (?, ?, ?, ?)
            """,
            (sale.date, sale.item, sale.amount, sale.customer_id),
        )

    conn.commit()
    conn.close()
Python

4. 一本の線を通すメイン

# main.py
from services.csv_input import read_csv
from services.sales_processing import validate_and_convert
from repositories.sales_repository import save_sales
from repositories.schema import create_tables

def main() -> None:
    """
    入力 → データ処理 → 保存 の基本機能を実行します。
    """
    create_tables()
    rows = read_csv("sales_sample.csv")
    sales = validate_and_convert(rows)
    save_sales(sales)
    print("基本機能が正常に動作しました")


if __name__ == "__main__":
    main()
Python

Day 86のまとめ ― 「まずは一本の線を通す。それが“作品”の始まり」

今日のテーマは、

  • 入力
  • データ処理
  • 保存

という、システムの 最重要な3ステップ を 実際のコードとして形にすることでした。

この一本の線が通った瞬間、 プロジェクトは「設計図」から、 「動く作品」 に変わります。

Day 86を終えた今、 みなさんのプロジェクトには、 すでに「心臓の鼓動」のようなものが宿っています。

ここから先は、

  • 集計機能
  • API提供
  • レポート出力
  • テスト

などを少しずつ足していきながら、 作品としての完成度を高めていく時間です。

でも、そのすべての土台になっているのは、 今日作った 「入力 → 処理 → 保存」 の一本の線。

それを、誇っていい一歩として、 静かに、でも確かに、胸に置いておいてください。

タイトルとURLをコピーしました