(Python)类的练习与巩固(图书管理系统扩展)(类与方法的基础教程)(if条件扩展)(动态类型)(Python教程)
目录
源代码:
代码详解:
新需求
步骤引导
第一步:创建 Student 类并初始化属性
第二步:给 Student 类添加 “借阅图书” 方法
第三步:添加 “归还图书” 方法
第四步:添加 “查看已借图书” 方法
第五步:整合两个类并测试
运行结果说明
核心知识点
多说一句(重点代码解析):
1.学生类的def borrow_book()方法,和图书类的方法不是重名了吗?
1. 方法属于不同的类,作用域不同
2. 调用方式不同,不会冲突
3. 这样设计更符合 “自然语言”
举个生活中的例子
2.if book in self.borrowed_books:有没有其他表现形式?
方法 1:用循环遍历判断
方法 2:用列表的 count() 方法
方法 3:用 any() 函数配合生成器
哪种最好?
3.for book in self.borrowed_books: 是什么?
举个例子
4.if book.is_available():if self.borrowed_books:为什么判断不用加条件?
先看 if self.borrowed_books:
再看 if book.is_available():
为什么可以这样写?
源代码:
class Book:def __init__(self,title,author,publisher,is_borrowed=False):self.title=titleself.author=authorself.publisher=publisherself.is_borrowed=is_borroweddef show_info(self):status="已借出"if self.is_borrowed==True else"未借出"print(f"书名:《{self.title}》")print(f"作者:{self.author}")print(f"出版社:{self.publisher}")print(f"状态:{status}")def borrow_book(self):if self.is_borrowed==False:self.is_borrowed=True print(f"《{self.title}》已经成功借出")else:print(f"抱歉《{self.title}》已经借出,无法再次借出")def return_book(self):if self.is_borrowed==True:self.is_borrowed=Falseprint(f"《{self.title}》已经成功归还")else:print(f"抱歉《{self.title}》未曾借出,无需归还")def is_available(self):if self.is_borrowed==False :print(f"《{self.title}》未曾借出")else:print(f"抱歉《{self.title}》已经借出")class Student:def __init__(self,name,student_id):self.name=nameself.student_id=student_idself.borrowed_books=[]def borrow_book(self,book):if book.is_available():book.borrow_book()self.borrowed_books.append(book)print(f"{self.name}成功借阅《{book.title}》")else:print(f"{self.name}无法借阅《{book.title}》,该书已被借出")def return_book(self,book):if book in self.borrowed_books:book.return_book()self.borrowed_books.remove(book)print(f"{self.name}成功归还《{book.title}》")else:print(f"{self.name}没有借阅《{book.title}》,无法归还")def show_borrowed_books(self):if self.borrowed_books:print(f"\n{self.name}(学号:{self.student_id})当前借阅的图书:")for book in self.borrowed_books:print(f"- 《{book.title}》")else:print(f"\n{self.name}当前没有借阅任何图书")book1 = Book("Python入门", "张三", "编程出版社")
book2 = Book("数据结构与算法", "李四", "科技出版社")
student = Student("小明", "2023001")
student.show_borrowed_books()
student.borrow_book(book1)
student.borrow_book(book2)
student.show_borrowed_books()
student.borrow_book(book1)
student.return_book(book1)
student.show_borrowed_books()
代码详解:
新需求
- 创建
Student
类,包含属性:姓名、学号、已借图书列表(初始为空) - 给学生类添加方法:借阅图书、归还图书、查看已借图书
- 让学生类和图书类联动:学生借阅图书时,图书状态改为 “已借出”;归还时改为 “未借出”
步骤引导
第一步:创建 Student 类并初始化属性
先定义学生的基本信息,重点是 borrowed_books
列表(用来记录学生借了哪些书):
class Student:def __init__(self, name, student_id):self.name = name # 学生姓名self.student_id = student_id # 学号(唯一标识)self.borrowed_books = [] # 已借图书列表,初始为空
第二步:给 Student 类添加 “借阅图书” 方法
学生借阅图书时,需要做这些检查:
- 图书是否可借(未被借出)
- 如果可借,将图书添加到学生的借阅列表
- 同时修改图书的借出状态(调用图书类的
borrow_book
方法)
class Student:def __init__(self, name, student_id):self.name = nameself.student_id = student_idself.borrowed_books = []# 借阅图书的方法(参数是一本图书对象)def borrow_book(self, book):# 检查图书是否可借if book.is_available():# 调用图书的borrow_book方法(修改图书状态)book.borrow_book()# 将图书添加到学生的借阅列表self.borrowed_books.append(book)print(f"{self.name}成功借阅《{book.title}》")else:print(f"{self.name}无法借阅《{book.title}》,该书已被借出")
第三步:添加 “归还图书” 方法
归还图书时,需要:
- 检查学生是否真的借了这本书
- 如果借了,从借阅列表中移除
- 同时修改图书的状态(调用图书类的
return_book
方法)
class Student:def __init__(self, name, student_id):self.name = nameself.student_id = student_idself.borrowed_books = []def borrow_book(self, book):if book.is_available():book.borrow_book()self.borrowed_books.append(book)print(f"{self.name}成功借阅《{book.title}》")else:print(f"{self.name}无法借阅《{book.title}》,该书已被借出")# 归还图书的方法(参数是一本图书对象)def return_book(self, book):# 检查这本书是否在学生的借阅列表中if book in self.borrowed_books:# 调用图书的return_book方法(修改图书状态)book.return_book()# 从借阅列表中移除self.borrowed_books.remove(book)print(f"{self.name}成功归还《{book.title}》")else:print(f"{self.name}没有借阅《{book.title}》,无法归还")
第四步:添加 “查看已借图书” 方法
class Student:def __init__(self, name, student_id):self.name = nameself.student_id = student_idself.borrowed_books = []def borrow_book(self, book):if book.is_available():book.borrow_book()self.borrowed_books.append(book)print(f"{self.name}成功借阅《{book.title}》")else:print(f"{self.name}无法借阅《{book.title}》,该书已被借出")def return_book(self, book):if book in self.borrowed_books:book.return_book()self.borrowed_books.remove(book)print(f"{self.name}成功归还《{book.title}》")else:print(f"{self.name}没有借阅《{book.title}》,无法归还")# 查看已借图书def show_borrowed_books(self):if self.borrowed_books: # 如果有已借图书print(f"\n{self.name}(学号:{self.student_id})当前借阅的图书:")for book in self.borrowed_books:print(f"- 《{book.title}》")else: # 如果没有借书print(f"\n{self.name}当前没有借阅任何图书")
第五步:整合两个类并测试
现在我们有了 Book
类(之前修正过的)和 Student
类,来测试它们的交互:
# 创建两本图书book1 = Book("Python入门", "张三", "编程出版社")book2 = Book("数据结构与算法", "李四", "科技出版社")# 创建一个学生student = Student("小明", "2023001")# 查看学生初始借阅情况student.show_borrowed_books()# 学生借阅第一本书student.borrow_book(book1)# 学生尝试借阅第二本书student.borrow_book(book2)# 查看借阅情况student.show_borrowed_books()# 学生尝试再次借阅第一本书(应该失败)student.borrow_book(book1)# 学生归还第一本书student.return_book(book1)# 查看最终借阅情况student.show_borrowed_books()
运行结果说明
小明当前没有借阅任何图书
《Python入门》状态更新为:已借出
小明成功借阅《Python入门》
《数据结构与算法》状态更新为:已借出
小明成功借阅《数据结构与算法》小明(学号:2023001)的借阅列表:
1. 《Python入门》
2. 《数据结构与算法》
《Python入门》已被借出
小明无法借阅《Python入门》,该书已被借出
《Python入门》状态更新为:未借出
小明成功归还《Python入门》小明当前没有借阅任何图书
核心知识点
- 类的交互:学生类通过调用图书类的方法(
borrow_book
、return_book
)来修改图书状态,体现了对象之间的协作。 - 对象存储:学生的
borrowed_books
列表直接存储图书对象,而不是字符串,这样可以直接操作图书的属性和方法。 - 逻辑检查:借阅 / 归还前的条件判断(是否可借、是否真的借出)让程序更严谨。
多说一句(重点代码解析):
1.学生类的def borrow_book()方法,和图书类的方法不是重名了吗?
1. 方法属于不同的类,作用域不同
- 图书类的
borrow_book
是图书自己的方法,作用是 “修改自己的借出状态”(比如从 “未借出” 变成 “已借出”) - 学生类的
borrow_book
是学生自己的方法,作用是 “学生执行借阅操作”(比如检查图书是否可借、把图书加入自己的借阅列表)
它们虽然名字一样,但属于不同的类,就像两个同名的人分别在两个不同的班级,不会混淆。
2. 调用方式不同,不会冲突
调用时需要通过具体的对象,所以能明确区分:
# 调用图书的borrow_book(图书自己修改状态)
book1.borrow_book()# 调用学生的borrow_book(学生执行借阅操作,参数是图书对象)
student1.borrow_book(book1)
3. 这样设计更符合 “自然语言”
比如我们说:
- “这本书被借出了” → 对应
book.borrow_book()
- “这个学生借了这本书” → 对应
student.borrow_book(book)
用相同的名字反而更符合我们的表达习惯,一看就知道是和 “借阅” 相关的操作。
举个生活中的例子
就像:
- 手机有 “充电” 功能(手机自己的方法:接收充电)
- 人有 “充电” 动作(人的方法:给手机充电)
虽然都叫 “充电”,但一个是手机的行为,一个是人的行为,完全不冲突,反而很容易理解~
所以这种 “同名不同类” 的方法在编程中是合理且常用的,不用特意修改名字哦!
2.if book in self.borrowed_books:有没有其他表现形式?
方法 1:用循环遍历判断
通过遍历 borrowed_books
列表,逐个对比是否为目标图书:
# 遍历借阅列表中的每一本书
has_book = False # 先假设没有
for b in self.borrowed_books:if b == book: # 对比当前书和目标书是否是同一本has_book = Truebreak # 找到后就跳出循环if has_book:# 执行归还操作...
else:print(f"{self.name}没有借阅《{book.title}》,无法归还")
这种方式更直观地展示了 “检查包含” 的底层逻辑,但代码比 in
关键字更长。
方法 2:用列表的 count()
方法
count(book)
会返回列表中与 book
匹配的元素数量,如果大于 0,说明包含这本书:
if self.borrowed_books.count(book) > 0:# 执行归还操作...
else:print(f"{self.name}没有借阅《{book.title}》,无法归还")
原理和 in
类似,但 count()
会遍历整个列表(即使找到匹配项也会继续检查),效率略低于 in
(in
找到后会立即停止)。
方法 3:用 any()
函数配合生成器
any()
函数判断是否有任意一个元素满足条件,这里检查是否有一本书等于目标书:
if any(b == book for b in self.borrowed_books):# 执行归还操作...
else:print(f"{self.name}没有借阅《{book.title}》,无法归还")
这种方式更偏向函数式编程风格,和 in
的效率相近。
哪种最好?
if book in self.borrowed_books:
是最简洁、高效且符合 Python 风格的写法,日常开发中优先使用这种。其他方式更多是帮助理解 “检查包含” 的不同实现思路,实际场景中很少需要替换。
本质上,这些方法都是基于 “对象身份” 判断的 —— 因为 borrowed_books
中存储的是图书对象本身,所以 book in 列表
会直接判断是否为同一个对象(而不是比较属性是否相同),这正是我们需要的逻辑~
3.for book in self.borrowed_books: 是什么?
这行代码是 for 循环遍历列表 的操作,作用是依次取出学生借阅列表中的每本图书,并打印出图书的标题。
我们拆解来看:
-
for book in self.borrowed_books:
self.borrowed_books
是存储学生已借图书的列表(里面放的是Book
类的实例对象)。- 这行的意思是:依次从借阅列表中取出每一个元素,暂时用变量
book
表示(每次循环,book
就代表列表中的一本书)。
-
print(f"- 《{book.title}》")
- 循环内部,对当前取出的
book
(一本图书对象)进行操作。 book.title
是访问这本书的title
属性(即书名)。- 用 f - 字符串格式化后,打印出类似
- 《Python入门》
这样的内容。
- 循环内部,对当前取出的
举个例子
如果学生的借阅列表是:
self.borrowed_books = [book1, book2]
(其中 book1
是《Python 入门》,book2
是《小王子》)
循环会分两次执行:
- 第一次:
book
代表book1
→ 打印- 《Python入门》
- 第二次:
book
代表book2
→ 打印- 《小王子》
简单说,这行代码的作用就是 “把学生借的所有书,一本一本列出来打印”,让我们能清晰看到学生借了哪些书~
4.if book.is_available():if self.borrowed_books:为什么判断不用加条件?
这是 Python 中一种简洁的 “真值判断” 写法,利用了数据类型的 “布尔特性”—— 不同类型的数据会被自动判断为 “真(True)” 或 “假(False)”,所以不需要额外加条件。
先看 if self.borrowed_books:
self.borrowed_books
是一个列表:
- 当列表为空时(
[]
),Python 会把它视为 “假(False)” - 当列表有元素时(比如
[book1, book2]
),会被视为 “真(True)”
所以 if self.borrowed_books:
等价于 if len(self.borrowed_books) > 0:
,意思是 “如果借阅列表里有书”。
再看 if book.is_available():
book.is_available()
是一个返回布尔值(True/False)的方法:
- 当图书可借时,这个方法返回
True
- 当图书不可借时,返回
False
所以 if book.is_available():
等价于 if book.is_available() == True:
,直接用返回的布尔值作为判断条件。
为什么可以这样写?
Python 的设计理念是 “简洁明了”,对于这些常见判断,允许省略冗余的条件:
- 列表、字符串、字典等 “容器类型”:空则为假,非空则为真
- 布尔值(True/False):可以直接作为判断条件
这种写法更符合自然语言习惯,比如:
- “如果有借书”(
if 借阅列表
)而不是 “如果借阅列表的长度大于 0” - “如果可借”(
if 可借状态
)而不是 “如果可借状态等于真”
熟练后会发现这样写更简洁高效哦~
注:该代码是本人自己所写,可能不够好,不够简便,欢迎大家指出我的不足之处。如果遇见看不懂的地方,可以在评论区打出来,进行讨论,或者联系我。上述内容全是我自己理解的,如果你有别的想法,或者认为我的理解不对,欢迎指出!!!如果可以,可以点一个免费的赞支持一下吗?谢谢各位彦祖亦菲!!!!