パッケージ構成に整理

このレッスンでできるようになること

1本のファイルに詰め込んでいた家計簿を、models と report に分けたパッケージの形に整理できるようになります。

パッケージはフォルダにした module です

第1章で、関数を別ファイルへ移して import することを学びました。ファイルが3本4本と増えてくると、今度はそのファイル自体が散らかります。そこで関係するファイルをフォルダにまとめ、フォルダごと import できるようにしたものがパッケージです。

kakeibo/ __init__.py models.py report.py

__init__.py は「このフォルダはパッケージです」という目印のファイルです。中身は空で構いません。この形にしておくと、外からは次のように呼べます。

from kakeibo.models import Expense from kakeibo.report import category_totals

kakeibo.models. は、フォルダの中のファイルを指しています。パスの区切りが . になっただけで、やっていることは第1章の自作 module の import と同じです。

どう分けるかは責務で決めます

ファイル名で迷ったら、そのコードが何の役目を持っているかで分けます。今回の家計簿なら次の2つです。

  • models.py — データの形。第7章で作った Expense クラスを置きます
  • report.py — データを読んで数える処理。合計やカテゴリ別集計を置きます

この分け方の良いところは、Expense に項目を1つ足したくなったときに models.py だけを開けばよく、集計の書き方を変えたくなったときは report.py だけを開けばよいことです。逆に「表示の関数と集計の関数が同じファイルに混ざっている」と、直したい場所を探すところから始まります。

この演習では中身をコードで書き出します

ふだんはエディタで models.py を作りますが、この学習環境ではファイルを1本しか書けません。そこで中身を文字列として持っておき、プログラムからファイルに書き出してから import します。

from pathlib import Path MODELS_SRC = """from dataclasses import dataclass @dataclass class Expense: name: str amount: int category: str date: str """ Path("kakeibo").mkdir(exist_ok=True) Path("kakeibo/models.py").write_text(MODELS_SRC, encoding="utf-8")

mkdir(exist_ok=True) は、すでにフォルダがあってもエラーにしない書き方です。write_text は第6章の pathlib で出てきたものです。

書き出した直後に import するときは、1行だけ添えるものがあります。

import importlib importlib.invalidate_caches()

Python は「どこにどのファイルがあるか」を一度調べたら覚えています。プログラムの実行中に新しく作ったフォルダは、その記憶に入っていません。invalidate_caches() はその記憶を捨てて、もう一度探し直させる命令です。この1行が無いと、たった今作ったばかりのパッケージが見つからず ModuleNotFoundError になります。

新しい文法はここまでです。あとは第7章までの道具で中身を書くだけです。

要件

  1. kakeibo フォルダを作り、init.py / models.py / report.py の3本を書き出す
  2. models.py に dataclass の Expense を定義する。属性は name, amount, category, date の4つ
  3. Expense に is_expensive メソッドを持たせる。amount が 1000 以上なら True を返す
  4. report.py に total_amount と category_totals を定義する。category_totals は Counter で返す
  5. 書き出したあと importlib.invalidate_caches() を呼んでから import する
  6. 支出は スーパー3200円食費, 電車代480円交通費, コンビニ850円食費, 技術書1600円教養 の4件を使う
  7. 1行目に 合計 6130円 の形で総額を表示する
  8. 2行目以降にカテゴリ名の昇順で 食費 4050円 の形で表示する
  9. 最後の行に 高額 2件 の形で is_expensive が True の件数を表示する

入出力例

出力: "合計 6130交通費 480教養 1600食費 4050高額 2件"

ヒント

生田 陸人
ゆめさくエンジニア / 現役ソフトウェアエンジニア
編集 LuaGate編集部
main.py
学習モード

メモ

パッケージ構成に整理

⌘S で保存