システム開発入門の第21週目では、前週に実装した図書館貸出システムを題材に、Pythonの継承で本の種類ごとの貸出条件を表し、番号入力で操作するコンソールUIを組み立てました。
コードを増やすだけでなく、既存の仕組みをどう再利用し、利用者に処理結果をどう伝えるかまでが今回の学習範囲です。
今回の実習で取り組んだこと
授業では、図書館貸出システムに本の種類を追加し、その機能をコンソールから操作できるようにしました。
Bookを継承したReferenceBookとMagazineを作る- 本の種類に応じて
lend()の動作を変える - 検索、貸出、返却、終了を番号で選べるメニューを作る
- 不正な入力や処理の失敗をメッセージで伝える
- 表示内容と操作の流れを繰り返し確認する
「機能を増やすだけではなく、ユーザーが直感的に操作できる仕組みづくりも大切です。今回は継承で新しい本の種類を追加し、操作画面を整えましょう。」
田中先生
継承で本の種類ごとの貸出条件を分ける
継承は、既存のクラスが持つ属性や操作を土台にして、別のクラスを作る書き方です。
この例ではBookが親クラス、ReferenceBookとMagazineが子クラスに当たります。
子クラス側で親クラスと同じ名前のメソッドを定義し直すことをオーバーライドと呼びます。
どちらの子クラスもlend()をオーバーライドするため、呼び出し側は同じlend()という操作を使いながら、本の種類に応じた結果を受け取れます。
from book import Book
class ReferenceBook(Book):
def lend(self):
# 参考図書は貸出不可
print(f"{self.title} は参考図書のため貸出できません。")
return False
class Magazine(Book):
def __init__(self, title, author, issue):
super().__init__(title, author)
self.issue = issue
def lend(self):
# このプログラムでは最新号のみ貸出可能
if self.is_available and self.issue == "最新号":
self.is_available = False
return True
print(f"{self.title} の{self.issue}は貸出不可です。")
return False
ReferenceBookの動作
ReferenceBook.lend()は貸出処理を行わず、理由を表示してFalseを返します。
親クラスの貸出処理をそのまま使わず、参考図書という種類に固有の条件をメソッドにまとめています。
Magazineの動作
super().__init__(title, author)は、親クラスであるBookの初期化処理を呼び出します。
その後で雑誌に必要なissueを追加するため、共通の初期化処理と雑誌固有の情報を分けて読めます。
Magazine.lend()は、貸出可能な状態であり、かつissueが「最新号」のときだけTrueを返します。
| クラス | この例で加えた規則 | lend()の結果 |
|---|---|---|
ReferenceBook |
参考図書は貸し出さない | 理由を表示してFalse |
Magazine |
貸出可能な最新号だけを対象にする | 条件を満たせばTrue、それ以外はFalse |
コンソールUIで操作の入口を作る
ユーザーインターフェース(UI)は、利用者がシステムに指示を出し、結果を受け取る接点です。
今回のコンソールUIでは、画面上のボタンの代わりに番号と文字列を入力します。
掲載コードでは、show_menu()とrun_console()を独立した関数として定義し、LibraryとMemberのオブジェクトを受け取って処理しています。
def show_menu():
print("\n=== 図書館メニュー ===")
print("1. 本を検索する")
print("2. 本を借りる")
print("3. 本を返す")
print("4. 終了")
def run_console(library, member):
while True:
show_menu()
choice = input("番号を入力してください:")
if choice == "1":
title = input("検索する本のタイトル:")
results = library.find_book(title)
print([b.title for b in results] or "該当する本はありません")
elif choice == "2":
title = input("借りたい本のタイトル:")
results = library.find_book(title)
if results and member.borrow(results[0]):
print("貸出が完了しました!")
else:
print("貸出に失敗しました。")
elif choice == "3":
title = input("返却する本のタイトル:")
book = next((b for b in member.borrowed if b.title == title), None)
if book and member.give_back(book):
print("返却が完了しました!")
else:
print("返却に失敗しました。")
elif choice == "4":
print("ご利用ありがとうございました!")
break
else:
print("無効な入力です。もう一度選んでください。")
入力から処理結果までの流れ
while Trueでメニューを繰り返し表示します。input()で利用者の選択を文字列として受け取ります。ifとelifで、検索、貸出、返却の処理に振り分けます。- 「4」が入力されたときは
breakでループを終えます。 - それ以外の入力には、選び直すための案内を表示します。
検索結果がない場合や貸出条件を満たさない場合にも処理を止めず、メニューへ戻れる構造です。
動作テストで確認したい分岐
後半の実習では、メニュー番号、案内文、検索結果の表示を調整しながら動作を確認しました。
このコードでは、成功する操作だけでなく、次の分岐を分けて試すと動作を把握しやすくなります。
- 検索した本が見つかる場合と見つからない場合
- 通常の貸出が成功する場合と、参考図書などの条件によって失敗する場合
- 借りている本を返す場合と、該当する本が貸出一覧にない場合
- 「1」から「4」以外の値を入力した場合
掲載コードの貸出失敗メッセージは、検索結果がない場合と本側の条件で貸し出せない場合を区別していません。
発展課題として、失敗理由ごとに案内を分けると、利用者が次に何をすべきか判断しやすくなります。
同じタイトルの本が複数見つかった場合にresults[0]だけを選ぶ点も、識別番号や候補一覧を使う設計へ進むときの検討材料になります。
継承とUIを一つの処理につなげる
今回の実習では、継承によって本ごとの規則を整理し、コンソールUIによって検索、貸出、返却の入口を一つにまとめました。
クラスの構造が整っていても、利用者に結果が伝わらなければ操作は続けられません。
反対に、メニューが読みやすくても、貸出条件がコードの各所に散らばれば変更や確認が難しくなります。
処理の役割と利用者への案内を対応させることが、今回の実習から持ち帰れる設計上のポイントです。
次週は外部API連携へ
次週の授業では、天気情報や地図データなどを例に、外部サービスと通信するための基礎へ進みました。
続きは第22週目の外部API連携入門で紹介しています。
この記事に関連する株式会社greedenの取り組み
図書館システムの実習で学んだのは、機能の追加と使いやすい操作設計を同時に考える姿勢です。株式会社greedenは、要件整理から設計、実装、テスト、保守まで一貫してWebシステム開発を支援しています。
