Python教程42:综合项目-图书管理系统

“纸上得来终觉浅,绝知此事要躬行。”

经过第四部分12课的学习,我们掌握了OOP的核心概念。今天通过一个完整的图书管理系统,综合运用所学知识。

1. 项目需求

功能需求

基本功能

  • 图书管理:添加、删除、搜索、借阅、归还
  • 用户管理:注册、借阅记录
  • 分类管理:按类别组织图书

进阶功能

  • 数据持久化(JSON)
  • 借阅期限和逾期管理
  • 统计报表

技术要求

  • 使用类和对象
  • 继承和多态
  • 抽象基类
  • 属性管理(@property)
  • 异常处理
  • 文件操作

2. 系统设计

类设计

Library System
├── Book(图书基类)
│   ├── PhysicalBook(实体书)
│   └── EBook(电子书)
├── User(用户类)
├── Library(图书馆类)
├── BorrowRecord(借阅记录)
└── Storage(存储类)

3. 核心实现

Book基类

 1from abc import ABC, abstractmethod
 2from datetime import datetime
 3
 4class Book(ABC):
 5    """图书抽象基类"""
 6    
 7    def __init__(self, isbn, title, author, category):
 8        self.isbn = isbn
 9        self.title = title
10        self.author = author
11        self.category = category
12        self.is_borrowed = False
13    
14    @abstractmethod
15    def get_type(self):
16        """获取图书类型"""
17        pass
18    
19    def to_dict(self):
20        """序列化"""
21        return {
22            'isbn': self.isbn,
23            'title': self.title,
24            'author': self.author,
25            'category': self.category,
26            'is_borrowed': self.is_borrowed,
27            'type': self.get_type()
28        }
29    
30    def __str__(self):
31        status = "已借出" if self.is_borrowed else "可借阅"
32        return f"{self.title} by {self.author} ({status})"
33
34class PhysicalBook(Book):
35    """实体书"""
36    def __init__(self, isbn, title, author, category, location):
37        super().__init__(isbn, title, author, category)
38        self.location = location  # 书架位置
39    
40    def get_type(self):
41        return "physical"
42    
43    def to_dict(self):
44        data = super().to_dict()
45        data['location'] = self.location
46        return data
47
48class EBook(Book):
49    """电子书"""
50    def __init__(self, isbn, title, author, category, file_size):
51        super().__init__(isbn, title, author, category)
52        self.file_size = file_size  # 文件大小(MB)
53    
54    def get_type(self):
55        return "ebook"
56    
57    def to_dict(self):
58        data = super().to_dict()
59        data['file_size'] = self.file_size
60        return data

User类

 1class User:
 2    """用户类"""
 3    
 4    def __init__(self, user_id, name, email):
 5        self.user_id = user_id
 6        self.name = name
 7        self.email = email
 8        self.borrowed_books = []  # ISBN列表
 9    
10    def can_borrow(self, max_books=5):
11        """检查是否可以借阅"""
12        return len(self.borrowed_books) < max_books
13    
14    def borrow_book(self, isbn):
15        """借阅图书"""
16        if isbn not in self.borrowed_books:
17            self.borrowed_books.append(isbn)
18    
19    def return_book(self, isbn):
20        """归还图书"""
21        if isbn in self.borrowed_books:
22            self.borrowed_books.remove(isbn)
23    
24    def to_dict(self):
25        return {
26            'user_id': self.user_id,
27            'name': self.name,
28            'email': self.email,
29            'borrowed_books': self.borrowed_books
30        }
31    
32    def __str__(self):
33        return f"User({self.name}, 已借{len(self.borrowed_books)}本)"

BorrowRecord类

 1class BorrowRecord:
 2    """借阅记录"""
 3    
 4    def __init__(self, user_id, isbn, borrow_date=None):
 5        self.user_id = user_id
 6        self.isbn = isbn
 7        self.borrow_date = borrow_date or datetime.now()
 8        self.return_date = None
 9        self.due_date = self.borrow_date + timedelta(days=30)
10    
11    @property
12    def is_overdue(self):
13        """是否逾期"""
14        if self.return_date:
15            return False
16        return datetime.now() > self.due_date
17    
18    def mark_returned(self):
19        """标记为已归还"""
20        self.return_date = datetime.now()
21    
22    def to_dict(self):
23        return {
24            'user_id': self.user_id,
25            'isbn': self.isbn,
26            'borrow_date': self.borrow_date.isoformat(),
27            'due_date': self.due_date.isoformat(),
28            'return_date': self.return_date.isoformat() if self.return_date else None
29        }

Library类

  1class Library:
  2    """图书馆类"""
  3    
  4    def __init__(self, name):
  5        self.name = name
  6        self.books = {}  # ISBN -> Book
  7        self.users = {}  # user_id -> User
  8        self.records = []  # BorrowRecord列表
  9    
 10    def add_book(self, book):
 11        """添加图书"""
 12        if book.isbn in self.books:
 13            raise ValueError(f"图书{book.isbn}已存在")
 14        self.books[book.isbn] = book
 15    
 16    def remove_book(self, isbn):
 17        """删除图书"""
 18        if isbn not in self.books:
 19            raise ValueError(f"图书{isbn}不存在")
 20        if self.books[isbn].is_borrowed:
 21            raise ValueError("图书已借出,无法删除")
 22        del self.books[isbn]
 23    
 24    def register_user(self, user):
 25        """注册用户"""
 26        if user.user_id in self.users:
 27            raise ValueError(f"用户{user.user_id}已存在")
 28        self.users[user.user_id] = user
 29    
 30    def borrow_book(self, user_id, isbn):
 31        """借阅图书"""
 32        # 验证
 33        if user_id not in self.users:
 34            raise ValueError("用户不存在")
 35        if isbn not in self.books:
 36            raise ValueError("图书不存在")
 37        
 38        user = self.users[user_id]
 39        book = self.books[isbn]
 40        
 41        if book.is_borrowed:
 42            raise ValueError("图书已被借出")
 43        if not user.can_borrow():
 44            raise ValueError("借阅数量已达上限")
 45        
 46        # 借阅
 47        book.is_borrowed = True
 48        user.borrow_book(isbn)
 49        record = BorrowRecord(user_id, isbn)
 50        self.records.append(record)
 51        
 52        return f"{user.name}成功借阅《{book.title}》"
 53    
 54    def return_book(self, user_id, isbn):
 55        """归还图书"""
 56        if user_id not in self.users:
 57            raise ValueError("用户不存在")
 58        if isbn not in self.books:
 59            raise ValueError("图书不存在")
 60        
 61        user = self.users[user_id]
 62        book = self.books[isbn]
 63        
 64        if not book.is_borrowed:
 65            raise ValueError("图书未被借出")
 66        
 67        # 归还
 68        book.is_borrowed = False
 69        user.return_book(isbn)
 70        
 71        # 更新记录
 72        for record in reversed(self.records):
 73            if (record.user_id == user_id and 
 74                record.isbn == isbn and 
 75                not record.return_date):
 76                record.mark_returned()
 77                break
 78        
 79        return f"{user.name}成功归还《{book.title}》"
 80    
 81    def search_books(self, keyword):
 82        """搜索图书"""
 83        results = []
 84        keyword = keyword.lower()
 85        for book in self.books.values():
 86            if (keyword in book.title.lower() or 
 87                keyword in book.author.lower() or
 88                keyword in book.category.lower()):
 89                results.append(book)
 90        return results
 91    
 92    def get_statistics(self):
 93        """获取统计信息"""
 94        total_books = len(self.books)
 95        borrowed = sum(1 for book in self.books.values() if book.is_borrowed)
 96        overdue = sum(1 for record in self.records if record.is_overdue)
 97        
 98        return {
 99            'total_books': total_books,
100            'available': total_books - borrowed,
101            'borrowed': borrowed,
102            'total_users': len(self.users),
103            'overdue_records': overdue
104        }

4. 使用示例

 1# 创建图书馆
 2library = Library("市图书馆")
 3
 4# 添加图书
 5book1 = PhysicalBook("978-1", "Python编程", "作者A", "编程", "A-101")
 6book2 = EBook("978-2", "数据结构", "作者B", "编程", 15.5)
 7library.add_book(book1)
 8library.add_book(book2)
 9
10# 注册用户
11user = User("U001", "张三", "zhang@example.com")
12library.register_user(user)
13
14# 借阅流程
15print(library.borrow_book("U001", "978-1"))
16print(library.borrow_book("U001", "978-2"))
17
18# 搜索
19results = library.search_books("Python")
20for book in results:
21    print(book)
22
23# 统计
24stats = library.get_statistics()
25print(f"总藏书:{stats['total_books']}")
26print(f"可借阅:{stats['available']}")
27print(f"已借出:{stats['borrowed']}")
28
29# 归还
30print(library.return_book("U001", "978-1"))

5. 知识点回顾

这个项目运用了:

  • 类和对象:Book、User、Library等
  • 继承:PhysicalBook、EBook继承Book
  • 抽象基类:Book使用ABC
  • 多态:不同类型的书有不同实现
  • 属性:@property装饰器
  • 异常处理:验证和错误处理
  • 封装:数据和方法组织
  • 组合:Library包含Books和Users

6. 小结

通过图书管理系统项目,我们综合运用了OOP的核心概念。第四部分(面向对象编程)到此结束。

已学内容

  • 类与对象、继承、多态
  • 魔术方法、类方法、静态方法
  • 属性、描述符
  • 抽象基类、多重继承
  • 元类、设计模式
  • 最佳实践

面向对象是Python编程的重要范式,掌握它能显著提升代码组织能力。


练习题

  1. 为系统添加数据持久化(JSON文件)
  2. 实现图书预约功能
  3. 添加GUI界面(tkinter)

本文代码示例

关注公众号:极客老墨

更多 AI 应用开发、工程实践和效率工具分享,欢迎扫码关注。

极客老墨微信公众号二维码

相关阅读