第 08 章「アプリを作る ── CLIツール、Fletアプリ、Flutterアプリ」の主張を裏付ける。
章のどの主張に対応するか
写真整理アプリ(撮影日でフォルダ分け):
- CLI で書く: 30 行の Python、開発時間 30 分、配布は GitHub に置くだけ
- iOS アプリで作る: Swift で 200 行、Xcode 環境 50 GB、App Store 審査 1 週間、年会費 $99
(章本文「実例: 数字で見る」より)
実際に書いてみると 約 90 行 の Python(EXIF を自前で読む実装込み)。 50 枚を 0.044 秒 で振り分けた。
やること
- 入力を作る:
generate_samples.pyで EXIF 入りの 1×1 JPEG を 50 枚生成 (撮影日を 2026-01〜2026-06 にバラす) - 整理する:
photo_organizer.py photos -o out/by-month --copy - 検算する: 結果フォルダのファイル数を月別に表示
すべて make all 一発。
構成
example-1/
├── README.md
├── photo_organizer.py ── 本体 CLI(EXIF 読み + フォルダ振り分け)
├── generate_samples.py ── サンプル JPEG 生成(EXIF DateTimeOriginal を埋め込む)
├── Makefile
├── results.md
├── photos/ ── 入力(50 枚の JPEG)
└── out/by-month/
├── 2026-01/ ── 11 枚
├── 2026-02/ ── 8 枚
├── 2026-03/ ── 10 枚
├── 2026-04/ ── 3 枚
├── 2026-05/ ── 5 枚
└── 2026-06/ ── 13 枚
実行
# 標準ライブラリだけで動く(Pillow 不要)
python3 generate_samples.py
python3 photo_organizer.py photos -o out/by-month --copy
# あるいは
make clean && make all
なぜこれが「実例」になるのか
「撮影日で写真を分ける」── これを Swift / Xcode で iOS アプリとして作ると:
- Xcode + iOS SDK = 約 50 GB の開発環境
- Apple Developer Program 年会費 $99
- 200 行の Swift + UI 実装
- App Store 審査 1 週間以上
- ユーザは App Store からインストール、iOS 限定
CLI で書くと:
- Python だけ(Pillow すら不要、EXIF を 50 行で自前パース)
- ファイル 1 個 (
photo_organizer.py約 90 行) - 配布は GitHub に置くか pip パッケージ
- 即実行可能、Mac / Windows / Linux どこでも動く
- 1,000 枚処理しても 数秒
しかも、他のシェルツールと組み合わせられる:
# 1 年分のスマホ写真を整理して NAS に同期
python3 photo_organizer.py ~/Pictures/iphone -o /nas/photos
# RAW + JPEG の組み合わせも対応
find . -name "*.CR3" -o -name "*.jpg" | xargs python3 photo_organizer.py ...
# 古い写真を 1 年単位の zip にする
python3 photo_organizer.py photos -o /tmp/sorted
for d in /tmp/sorted/*/; do zip -r "$(basename $d).zip" "$d"; done
GUI が要らない処理に GUI を被せると、他のものと組み合わせるとき GUI が壁になる。CLI のままなら、cron に入れて毎晩走らせることもできる。 これが章で言う「まず CLI から」の意味。
GUI が必要になったら(Flet で Python のまま GUI 化、それでも足りなければ Flutter)。 ステップを上げる順序がある。
EXIF を自前で読む
このスクリプトの面白いところは、Pillow を使わずに EXIF DateTimeOriginal
(tag 0x9003) を 50 行で読んでいる点。標準ライブラリ struct だけで
JPEG → APP1 → TIFF → IFD → ExifIFD を辿る。
「まず Claude にアウトラインを書いてもらって、自分で詰める」── このサイズの コードはまさに章 04 で言う「Claude が書く、人間が読む」の対象。
計測結果 — 第 08 章 example-1
実行環境: Linux 6.18 / Python 3.x(標準ライブラリのみ)
規模と性能(主目的)
| 項目 | 数値 |
|---|---|
photo_organizer.py 行数 |
約 90 行(EXIF 読み込み込み) |
| 依存 | 標準ライブラリのみ |
| 処理対象 | 50 枚の JPEG |
| 処理時間 | 0.044 秒 |
| 1 枚あたり | 約 0.9 ms |
| 1,000 枚処理(推定) | 約 0.9 秒 |
章本文との比較
| 項目 | iOS アプリ | この CLI |
|---|---|---|
| 開発環境のディスク | Xcode + iOS SDK = 50 GB | 0(Python が入っていれば終わり) |
| 年会費 | Apple Developer $99 | 0 |
| コード行数 | Swift で約 200 行 + UI | 約 90 行 |
| 配布までの時間 | App Store 審査 1 週間以上 | GitHub に push して終わり |
| 動く OS | iOS のみ | macOS / Windows / Linux |
| 1 ヶ月後の修正 | 再ビルド + 再審査 | エディタで直して終わり |
実行ログ(make all)
=== 撮影日でフォルダ分け ===
copy IMG_0001.jpg → by-month/2026-04/IMG_0001.jpg
copy IMG_0002.jpg → by-month/2026-02/IMG_0002.jpg
...
50 ファイル処理完了
real 0m0.044s
user 0m0.037s
sys 0m0.008s
=== 結果 ===
2026-01 : 11 枚
2026-02 : 8 枚
2026-03 : 10 枚
2026-04 : 3 枚
2026-05 : 5 枚
2026-06 : 13 枚
── 合計 50 枚を 6 フォルダに振り分け
配布
# 1. GitHub に push して終わり
git add photo_organizer.py
git commit -m "Photo organizer CLI"
git push
ユーザは:
curl -O https://raw.githubusercontent.com/you/repo/main/photo_organizer.py
python3 photo_organizer.py ~/Pictures -o ~/sorted-photos
これで完了。App Store も Google Play も要らない。
PyPI に上げるなら:
# pyproject.toml を 1 個作って
pip install build twine
python3 -m build
twine upload dist/*
これで pip install photo-organizer で世界中に配布される。
CLI から GUI に上げる(必要があれば)
CLI で動くものを、Flet で 30 行追加するだけで GUI 化できる:
import flet as ft
import photo_organizer
def main(page: ft.Page):
src = ft.TextField(label="入力")
dst = ft.TextField(label="出力")
def run(e): photo_organizer.organize(src.value, dst.value)
page.add(src, dst, ft.ElevatedButton("整理", on_click=run))
ft.app(target=main)
Flutter で書き直すなら 1 ヶ月、Flet なら 1 時間。CLI のロジックは そのまま再利用される。これが章で言う「CLI を一段ずつ昇格させる」。
再現手順
# Pillow も python-docx も不要、Python 3 だけ
make clean && make all