Python | 1 日 120 分 × 7 日アプリ学習:CSVファイル読み書きアプリ(中級編)

Web APP Python
スポンサーリンク

7日目のゴール

7日目のテーマは
「CSVファイル読み書きアプリの“全体像”を、自分の言葉で説明できるようになること」 です。

ここまで 6 日間であなたは、

csv.reader / csv.writer
csv.DictReader / csv.DictWriter
集計・フィルタ・ソート
エラー行のスキップ・分離
小さなヘルパー関数によるリファクタリング

を通して、
「CSVを使った実務データ処理」を一通り体験してきました。

今日はそれを「バラバラのテクニック」ではなく、
ひとつのアプリとして頭の中でつながった状態にする
ことを目指します。


アプリ全体を一文で説明してみる

どんなアプリを作ったのか

まず、この 7 日間で作ったアプリを
あえて一文で表現してみます。

「社員情報のCSVを読み込み、集計・抽出・エラー分離などをメニューから選んで実行できる、小さな実務用CSVユーティリティ」

もう少し分解すると、こうなります。

ひとつの入力CSV(employees_dirty.csv)を対象にする
起動時に一度だけCSVを読み込む
メニューから機能を選ぶ
選んだ機能が、読み込んだデータに対して処理を行う
必要に応じて、別CSVに結果を書き出す

つまり、
「CSVを中心にした、対話型のバッチツール」
のようなイメージです。


コアとなる「データの流れ」を整理する

読む → 加工する → 出す

このアプリの本質的な流れは、たったこれだけです。

CSVファイルからデータを読む
Pythonの中で加工・集計・フィルタする
必要なら、別のCSVとして書き出す

これを、もう少し具体的に追ってみます。

最初に load_employees(INPUT_FILE) が呼ばれ、
csv.DictReader で全行を辞書のリストとして読み込む。

その後は、メニューで選ばれた機能に応じて、
そのリスト(rows)を渡して処理する。

表示系の機能(一覧表示・集計)は、
rows を読みながら print するだけで完結する。

書き出し系の機能(30歳以上の抽出・エラー行の出力)は、
rows から条件に合う行だけを集め、
csv.DictWriter で別CSVに書き出す。

どの機能も、
「入力は rows(辞書のリスト)」
「出力は print か CSVファイル」
という共通の形になっています。


ヘルパー関数が担っている役割を理解する

to_int_or_none と is_valid_employee_row

6日目で導入したヘルパー関数は、
アプリの「見通し」を良くするための重要なピースです。

to_int_or_none(text) は、

空文字や変な文字列を None に変換する
数値として使えるものだけ int にして返す

という「数値変換のルール」を一箇所にまとめた関数でした。

これによって、

どの機能でも「数値変換の仕方」が統一される
仕様変更(例:空文字は 0 とみなしたい)があっても、この関数だけ直せばよい

という状態になっています。

is_valid_employee_row(row) は、

年齢が数値として解釈できるか
給与が数値として解釈できるか
部署が空欄ではないか

といった「行の妥当性チェック」を一箇所にまとめた関数でした。

これによって、

「どの行を“正常”とみなすか」が明確になる
エラー行の抽出・スキップが一貫したルールで行える

ようになっています。

この二つのヘルパーは、
「データのルールをコードの真ん中に置く」
という、とても大事な設計の一歩です。


各機能を「言葉で説明できるか」確認する

例 1: 部署ごとの給与集計

この機能を、コードを見ずに説明してみます。

rows の各行について、
まず is_valid_employee_row で「有効な行かどうか」を判定する。

有効な行だけを対象に、
部署名をキーにした辞書(stats)に
給与の合計と件数をためていく。

最後に、部署ごとに
合計と平均を計算して表示する。

ここで大事なのは、
「どの行を使うか」と「どう集計するか」が
頭の中で分かれていることです。

例 2: 30歳以上の社員を別CSVに書き出す

この機能も、言葉で追ってみます。

rows の各行について、
is_over_30(row) で「30歳以上かどうか」を判定する。

True の行だけを filtered に集める。

filtered が空でなければ、
元のヘッダー(fieldnames)を使って
csv.DictWriter で output_over30.csv に書き出す。

ここでも、
「条件判定」と「書き出し」が
きれいに分かれているのが分かると思います。

例 3: エラー行の書き出し

この機能は、こう説明できます。

rows の各行について、
is_valid_employee_row(row) が False のものだけを
error_rows に集める。

error_rows があれば、
元のヘッダーを使って
csv.DictWriter で error.csv に書き出す。

つまり、
「正常行の定義」と「エラー行の定義」が
同じ関数を基準にしている、ということです。


「どこを変えれば何が変わるか」をイメージする

仕様変更を頭の中でシミュレーションしてみる

ここからは、少し“設計者の目線”で考えてみます。

例えば、
「部署が空欄でも集計に含めたい」
という仕様変更が来たとします。

どこを直せばいいでしょうか。

答えは、is_valid_employee_row です。

部署が空欄なら False にしていた部分を、
条件から外せばいいだけです。

if department == "":
    return False
Python

この行を削るかコメントアウトすれば、
部署が空欄でも「有効な行」とみなされるようになります。

逆に、
「給与が 0 の行はエラー扱いにしたい」
という仕様変更なら、こう足せばいいです。

if salary is not None and salary <= 0:
    return False
Python

このように、

「仕様変更があったときに、
どの関数を触ればいいかがすぐ分かる」

という状態になっているかどうかが、
設計が整理されているかどうかの目安になります。


7日目のまとめ 今日つかんでほしい感覚

今日、そしてこの 7 日間でつかんでほしい本質は、これです。

csvモジュールは、「テキストとしてのCSV」を「Pythonのデータ」に変換してくれる橋渡し役。
DictReader / DictWriter を使うと、「列名でアクセスできる」実務的なコードになる。
実務データはきれいではないので、「変換できない値」「空欄」「エラー行」を前提に設計する。
ヘルパー関数(to_int_or_none, is_valid_employee_row など)に“ルール”を集約すると、コードが直しやすくなる。
アプリ全体を「読む → 加工する → 出す」という流れで捉えられれば、機能追加も怖くなくなる。

ここまで来たあなたは、
「csvモジュールを知っている人」ではなく、
“CSVを使った実務データ処理を、自分で設計できる人” の入り口に立っています。

この先は、
複数ファイルの突き合わせ、
日付の扱い、
クラス化やGUI化、
データベースとの連携

など、いくらでも広げていけます。

どこに進むにしても、
今日までに身につけた

「データをよく観察すること」
「ルールをコードに落とし込むこと」
「エラーを前提に設計すること」

この感覚は、ずっとあなたの武器になります。

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