国庆节10月1日
--


用面向对象做图书管理系统:抽象类 Member 与子类权限设计、Book 库存管理、JSON 数据加载与主循环

某社区图书馆要开发一个简单的图书管理系统,支持会员登录、图书借阅、图书归还。
| 功能 | 说明 |
|---|---|
| 会员登录 | 卡号 + 密码登录,登录成功后才能使用系统 |
| 借书 | 借阅库存有余量的图书 |
| 还书 | 归还已借阅的图书 |
| 查看我的借阅 | 展示当前会员已借阅的图书列表 |
| 退出系统 | — |
借阅规则:普通会员最多借 3 本;VIP 会员最多借 6 + VIP等级 本(等级默认 1)。库存不足或已达上限时不能借。
| 类 | 职责 |
|---|---|
Book | 一本书:编号、标题、作者、总数、可用数量(私有);借出/归还/查可用 |
Member(抽象类) | 会员公共部分:卡号、姓名、密码(私有)、借阅列表(私有);借书/还书/取密码/取借阅列表;抽象方法 get_max_books() |
NormalMember | 普通会员:get_max_books() 返回 3 |
VIPMember | VIP 会员:多一个 vip_level,get_max_books() 返回 6 + vip_level |
LibrarySystem | 图书馆系统:加载数据、登录、借书、还书、查看借阅、主循环 |
1from abc import ABC, abstractmethod2
3class Member(ABC): # 继承 ABC(Abstract Base Class)4 ...5 @abstractmethod6 def get_max_books(self) -> int:7 pass # 只有声明,没有实现抽象类是一种只能被继承、不能被直接实例化的类,作用是规定子类必须实现哪些方法,强制子类遵守统一的代码规范。Python 里的抽象类需要继承 abc 模块的 ABC,抽象方法用 @abstractmethod 装饰。
在这里它的价值是:Member 自己说不清”最多能借几本”,但要求每个子类必须说清楚。
1class Book:2 def __init__(self, book_id, title, author, total_num):3 self.book_id = book_id4 self.title = title5 self.author = author6 self.total_num = total_num7 self.__available_num = total_num # 可用数量(私有)8
9 def borrow_book(self):10 if self.__available_num > 0:11 self.__available_num -= 112 return True13 return False14
15 def return_book(self):16 self.__available_num += 117
18 def get_available_num(self):19 return self.__available_num1class Member(ABC):2 def borrow_book(self, book: Book):3 # 1. 达到最大借阅数量就不给借4 if len(self.__borrowed_books) >= self.get_max_books():5 print("借阅失败,您的借阅数量已达到最大限制!")6 return False7 # 2. 书籍还有余量才借8 if book.borrow_book():9 self.__borrowed_books.append(book)10 print(f"{self.name} 已成功借阅图书 {book.title}")11 return True12 else:13 print(f"借阅失败,图书 {book.title} 已被借完!")14 return False1class NormalMember(Member):2 def get_max_books(self) -> int:3 return 34
5
6class VIPMember(Member):7 def __init__(self, member_id, name, password, vip_level):8 super().__init__(member_id, name, password)9 self.vip_level = vip_level10
11 def get_max_books(self) -> int:12 return 6 + self.vip_level1class LibrarySystem:2 def __init__(self):3 self.books = {} # {"AI001": Book对象, ...}4 self.members = {} # {"V001": Member对象, ...}5 self.current_member: Member | None = None6 self.load_books_data()7 self.load_members_data()8
9 def load_members_data(self):10 with open("data/members.json", "r", encoding="utf-8") as f:11 members_data = json.load(f)12 for member in members_data:13 if member['卡号'].startswith('N'):14 self.members[member['卡号']] = NormalMember(member['卡号'], member['姓名'], member['密码'])15 elif member['卡号'].startswith('V'):16 self.members[member['卡号']] = VIPMember(member['卡号'], member['姓名'], member['密码'], member['会员等级'])数据结构对应关系:books.json 里是 [{"编号","标题","作者","数量"}, ...],members.json 里是 [{"卡号","姓名","密码","会员等级"}, ...](普通会员没有”会员等级”字段)。
1def run(self):2 if self.login(): # 登录成功才进菜单3 while True:4 print("1. 借阅图书 2. 归还图书 3. 查看借阅 4. 退出系统")5 choice = input("请选择操作(1-4): ")6 match choice:7 case "1": self.borrow_book()8 case "2": self.return_book()9 case "3": self.show_borrowed_books()10 case "4":11 print("退出系统, Bye Bye ~")12 break13 case _: print("无效的选项,请重新选择!")abc 模块的 ABC 类,抽象方法用 @abstractmethod 装饰get_available_num() 读取LibrarySystem 里 self.books 和 self.members 都是字典(类型),键是编号/卡号,值是对象 2-1 两种会员的借阅上限
写 NormalMember(上限 3)和 VIPMember(上限 6 + 等级),都继承抽象类 Member;分别实例化并打印各自的上限。
一级 · 思路:父类定规矩(抽象方法),子类各自给答案
二级 · 方法:class Member(ABC) + @abstractmethod def get_max_books(self)
三级 · 骨架:VIP 的 __init__ 里先 super().__init__(...) 再存 vip_level
1# 2-1(Book 类见 2-2)2from abc import ABC, abstractmethod3
4
5class Member(ABC):6 def __init__(self, member_id, name, password):7 self.member_id = member_id8 self.name = name9 self.__password = password10 self.__borrowed_books = []11
12 def get_borrowed_books(self):13 return self.__borrowed_books14
15 @abstractmethod16 def get_max_books(self) -> int:17 pass18
19
20class NormalMember(Member):21 def get_max_books(self) -> int:22 return 323
24
25class VIPMember(Member):26 def __init__(self, member_id, name, password, vip_level):27 super().__init__(member_id, name, password)28 self.vip_level = vip_level29
30 def get_max_books(self) -> int:31 return 6 + self.vip_level32
33
34# 测试35normal = NormalMember("N001", "小王", "123456")36vip = VIPMember("V001", "王林", "666888", 6)37print(normal.get_max_books(), vip.get_max_books()) # 3 12 2-2 图书库存
写 Book 类:总数量 + 私有可用数量;borrow_book() 库存为 0 时返回 False,return_book() 归还加一。
一级 · 思路:可用数量只让类内部改,外面只能读
二级 · 方法:self.__available_num / get_available_num()
三级 · 骨架:if self.__available_num > 0: self.__available_num -= 1; return True
1# 2-22class Book:3 def __init__(self, book_id, title, author, total_num):4 self.book_id = book_id5 self.title = title6 self.author = author7 self.total_num = total_num8 self.__available_num = total_num9
10 def borrow_book(self):11 if self.__available_num > 0:12 self.__available_num -= 113 return True14 return False15
16 def return_book(self):17 self.__available_num += 118
19 def get_available_num(self):20 return self.__available_num 2-3 借书流程
给 Member 加 borrow_book(book):先判断是否达到上限,再调用书的 borrow_book();达到上限时打印提示并返回 False。
一级 · 思路:两道关卡,先自己的额度、再书的库存
二级 · 方法:len(self.get_borrowed_books()) >= self.get_max_books()
三级 · 骨架:借成功要 append 到借阅列表里
1# 2-3:Member 类里的借书方法(Book、NormalMember 等定义见 2-1 / 2-2)2class Member(ABC):3 def __init__(self, member_id, name, password):4 self.member_id = member_id5 self.name = name6 self.__password = password7 self.__borrowed_books = []8
9 def borrow_book(self, book: Book):10 if len(self.__borrowed_books) >= self.get_max_books():11 print(f"{self.name} 借阅失败,已达到最大借阅数量 {self.get_max_books()} 本")12 return False13 if book.borrow_book():14 self.__borrowed_books.append(book)15 print(f"{self.name} 已成功借阅图书 {book.title}")16 return True17 print(f"{self.name} 借阅失败,图书 {book.title} 已被借完")18 return False19
20 def get_borrowed_books(self):21 return self.__borrowed_books22
23 @abstractmethod24 def get_max_books(self) -> int:25 pass26
27
28# 测试29normal = NormalMember("N001", "小王", "123456")30book = Book("AI001", "LangChain入门与实践", "李智慧", 2)31for i in range(4):32 normal.borrow_book(book) # 第 4 次会因达到上限而失败33print("剩余库存:", book.get_available_num())34
35book.return_book()36print("归还后剩余:", book.get_available_num())如果你喜欢,那么欢迎来到我的世界!
了解更多暂未播放



"生活不是等待暴风雨过去,而是学会在雨中跳舞。"—— 塞维涅夫人


