希望这个程序可以做到:
我们要思考:需要定义多少个类?每个类有怎样的属性和方法?
第一种用法是使用类生成实例对象。类作为实例对象的模版,每个实例创建后,都将拥有类的所有属性和方法,减少代码量,同一化和模块化
第二种用法是用类将多个函数(方法)打包封装在一起,让类中的方法相互配合,避免传参过多或过度使用global
回到项目:我们的处理对象是每本具体的书,而每本书都有自己的属性信息,所以我们可以定义一个Book类,利用Book类创建一个个书的实例,绑定属性(对应用法1)。
而这个管理系统的运行主体,是多个可供选择的功能的叠加,所以我们可以创建一个系统运行类BookManager,将查询书籍、添加书籍等功能封装成类中的方法以供调用(对应用法2)。
我们的预期效果是当实例化这个系统运行类的时候,会出现一个菜单,能让用户选择不同的功能,如下图所示:
那么,将上述要编写的两个类整理一下,这个程序的骨架就是这样:(注释里对应每个方法的功能)
接下来,我们可以先按这个框架来编写代码,解决编写过程中出现的每一个问题,让目标得实现。
代码实现,逐步执行
定义Book类
根据需求,每本书的基本属性都要有四个:书名、作家、推荐语和借阅状态。所以,我们可以利用初始化方法init,让实例被创建时自动获得这些属性。
为了后续方便参数传递,借阅状态state采用默认参数,用0来表示'未借出',1来表示'已借出'。
初始化方法定义完成后,一旦实例对象被创建,这几个属性就存在且可随时调用。
我们注意到系统里有一个功能是显示所有书籍信息,所以我们可以在Book类定义一个方法,当调用这个方法时,就能够打印出这本书的信息,加上循环,就能打印所有书籍的信息。希望的格式是这样的:
那么,我们可以在初始化方法的基础上定义一个show_info()方法,打印出每本书的信息:
只要在类中定义了str(self)方法,那么当使用print打印实例对象的时候,就会直接打印出在这个方法中return的数据。直接把上述代码里的方法名show_info(self)替换成str(self),留意最后一行调用的代码,然后点击运行:
类BookManager的编写
回顾:
用户输入数字执行相应的功能,程序内部调用的逻辑应该是:
这里需要用到多层条件判断语句
来看看show_all_book()方法,它的功能是打印出系统里所有书籍的信息。为了方便调试,验证代码是否写对了,我们可以先往书籍系统里添加几本书籍,也就是创建Book类的实例对象。
class Book:
def __init__(self, name, author, comment, state = 0):
self.name = name
self.author = author
self.comment = comment
self.state = state
def __str__(self):
if self.state == 0:
status = '未借出'
else:
status = '已借出'
return '名称:《%s》 作者:%s 推荐语:%s\n状态:%s ' % (self.name, self.author, self.comment, status)
class BookManager:
def __init__(self):
book1 = Book('惶然录','费尔南多·佩索阿','一个迷失方向且濒于崩溃的灵魂的自我启示,一首对默默无闻、失败、智慧、困难和沉默的赞美诗。')
book2 = Book('以箭为翅','简媜','调和空灵文风与禅宗境界,刻画人间之缘起缘灭。像一条柔韧的绳子,情这个字,不知勒痛多少人的心肉。')
book3 = Book('心是孤独的猎手','卡森·麦卡勒斯','我们渴望倾诉,却从未倾听。女孩、黑人、哑巴、醉鬼、鳏夫的孤独形态各异,却从未退场。', 1)
manager = BookManager()
上面的代码,在BookManager类的初始化方法中创建了3个Book类的实例对象。换言之,当创建实例manager时,book1、book2、book3就会生成。
当有多个对象的时候,就要考虑数据存储的方式。由于每个Book实例是并列平行的关系,所以可以用列表来存储。于是可以在类的开头定义一个空列表books,方便其他方法调用,然后把刚刚创建的Book实例添加到这个列表里。
如此一来,列表books里的每个元素都是基于Book类创建的实例对象,所以每个元素会【自动拥有Book类的方法】__str__。我们可以验证一下:
发现了吗?这个结果和我们想要定义的显示书籍信息的方法show_all_book()是一样的,所以我们可以把最后几行代码封装成方法。
我们将两个类的代码组合在一起,直接运行,遇到输入请输入数字1:
执行结果:
接下来我们来看第二个功能:添加书籍add_book()。
代码结构应该是这样的:当输入数字2的时候,就会跳转到对应的方法:
如果注释没有看懂,可以结合下面的数据流转图再理解一下:
把之前写好的代码整合在一起。
class Book:
def __init__(self, name, author, comment, state = 0):
self.name = name
self.author = author
self.comment = comment
self.state = state
def __str__(self):
status = '未借出'
if self.state == 1:
status = '已借出'
return '名称:《%s》 作者:%s 推荐语:%s\n状态:%s ' % (self.name, self.author, self.comment, status)
class BookManager:
books = []
def __init__(self):
book1 = Book('惶然录','费尔南多·佩索阿','一个迷失方向且濒于崩溃的灵魂的自我启示,一首对默默无闻、失败、智慧、困难和沉默的赞美诗。')
book2 = Book('以箭为翅','简媜','调和空灵文风与禅宗境界,刻画人间之缘起缘灭。像一条柔韧的绳子,情这个字,不知勒痛多少人的心肉。')
book3 = Book('心是孤独的猎手','卡森·麦卡勒斯','我们渴望倾诉,却从未倾听。女孩、黑人、哑巴、醉鬼、鳏夫的孤独形态各异,却从未退场。',1)
self.books.append(book1)
self.books.append(book2)
self.books.append(book3)
def menu(self):
print('欢迎使用流浪图书管理系统,每本沉默的好书都是一座流浪的岛屿,希望你有缘发现并着陆,为精神家园找到一片栖息地。\n')
while True:
print('1.查询所有书籍\n2.添加书籍\n3.借阅书籍\n4.归还书籍\n5.退出系统\n')
choice = int(input('请输入数字选择对应的功能:'))
if choice == 1:
self.show_all_book()
# self是实例对象的替身
elif choice == 2:
self.add_book()
elif choice == 3:
self.lend_book()
def show_all_book(self):
for book in self.books:
print(book)
def add_book(self):
new_name = input('请输入书籍名称:')
new_author = input('请输入作者名称:')
new_comment = input('请输入书籍推荐语:')
new_book = Book(new_name, new_author, new_comment)
self.books.append(new_book)
print('书籍录入成功!\n')
来看第三个功能:借阅书籍lend_book()
借阅功能lend_book()要怎么实现呢?可以先想想我们平时找人借东西,会出现哪几种情况?
这里有两个要点:1. 怎么判断这本书在不在系统里;2.怎么判断这本书有没有被借走。
首先,判断在不在系统里,我们可以采用遍历书籍列表books的方式,一旦输入的书籍名称和列表元素中的书籍名称出现匹配,就证明系统里有这本书。其次,如果书在系统里,有没有被借走可以根据实例属性state来判断,0表示'未借出',1表示'已借出'。
给出这两个判断的代码
class BookManager:
books = []
def __init__(self):
book1 = Book('惶然录','费尔南多·佩索阿','一个迷失方向且濒于崩溃的灵魂的自我启示,一首对默默无闻、失败、智慧、困难和沉默的赞美诗。')
book2 = Book('以箭为翅','简媜','调和空灵文风与禅宗境界,刻画人间之缘起缘灭。像一条柔韧的绳子,情这个字,不知勒痛多少人的心肉。')
book3 = Book('心是孤独的猎手','卡森·麦卡勒斯','我们渴望倾诉,却从未倾听。女孩、黑人、哑巴、醉鬼、鳏夫的孤独形态各异,却从未退场。',1)
self.books.append(book1)
self.books.append(book2)
self.books.append(book3)
def lend_book(self):
borrow_name = input('请输入你想借阅的书籍名称:')
for book in self.books:
# 遍历列表,此时books有三个元素,即book1,book2,book3三个实例
if book.name == borrow_name:
# 如果列表中有实例的属性name和输入的书籍名称相等
if book.state == 1:
# 借阅状态为'已借出'
print('你来晚一步,这本书已经被借走了噢')
break
# 一旦有对象满足条件,则退出for循环
else:
# 借阅状态为'未借出'
print('借阅成功!借了不看会变胖噢~')
book.state = 1
break
else:
continue
# 如果不满足book.name == borrow_name,则继续循环(这两行可以省略)
else:
print('这本书暂时没有收录在系统里呢')
注意这里有几个层级的else语句,我们可以看到最外层结构是for…else,表示的是当for循环里的对象都遍历完毕后,才执行else子句的内容。
也就是说,当列表里没有对象能够满足if book.name == borrow_name条件时,才会打印else子句的那一句话。(如果for循环内部有break子句,也不会执行)
代码是完成了,但归还书籍的时候,也会碰到类似的逻辑。为了不写重复的代码,我们可以【额外在类中定义一个方法】,专门检查输入的书名是否在书籍列表里。
换句话说:将上面lend_book()方法中检测书名的代码抽出来,封装成一个函数。这样就可以在借书和还书的代码里直接调用,不用两处重复写同样的代码。
为什么要分别返回书籍名称和None值呢?相信你读完下面的代码,就可以理解了。
我们将目前为止的代码,整合在一起
class Book:
def __init__(self, name, author, comment, state = 0):
self.name = name
self.author = author
self.comment = comment
self.state = state
def __str__(self):
status = '未借出'
if self.state == 1:
status = '已借出'
return '名称:《%s》 作者:%s 推荐语:%s\n状态:%s ' % (self.name, self.author, self.comment, status)
class BookManager:
#存储书籍的列表,每一个元素都是Book的实例对象
books = []
def __init__(self):
book1 = Book('惶然录','费尔南多·佩索阿','一个迷失方向且濒于崩溃的灵魂的自我启示,一首对默默无闻、失败、智慧、困难和沉默的赞美诗。')
book2 = Book('以箭为翅','简媜','调和空灵文风与禅宗境界,刻画人间之缘起缘灭。像一条柔韧的绳子,情这个字,不知勒痛多少人的心肉。')
book3 = Book('心是孤独的猎手','卡森·麦卡勒斯','我们渴望倾诉,却从未倾听。女孩、黑人、哑巴、醉鬼、鳏夫的孤独形态各异,却从未退场。',1)
self.books.append(book1)
self.books.append(book2)
self.books.append(book3)
def menu(self):
print('欢迎使用流浪图书管理系统,每本沉默的好书都是一座流浪的岛屿,希望你有缘发现并着陆,为精神家园找到一片栖息地。\n')
while True:
print('1.查询所有书籍\n2.添加书籍\n3.借出书籍\n4.归还书籍\n5.退出系统\n')
choice = int(input('请输入数字选择对应的功能:'))
if choice == 1:
self.show_all_book()
elif choice == 2:
self.add_book()
elif choice == 3:
self.lend_book()
elif choice == 4:
self.return_book()
elif choice == 5:
print('感谢使用!')
break
def show_all_book(self):
for book in self.books:
print(book)
print('')
def add_book(self):
new_name = input('请输入书籍名称:')
new_author = input('请输入作者名称:')
new_comment = input('请输入书籍推荐语:')
new_book = Book(new_name, new_author, new_comment)
self.books.append(new_book)
print('书籍录入成功!\n')
def check_book(self,name):
for book in self.books:
if book.name == name:
return book
else:
return None
def lend_book(self):
name = input('请输入书籍的名称:')
res = self.check_book(name)
if res != None:
if res.state == 1:
print('你来晚了一步,这本书已经被借走了噢')
else:
print('借阅成功,借了不看会变胖噢~')
res.state = 1
else:
print('这本书暂时没有收录在系统里呢')
manager = BookManager()
manager.menu()
return_book功能添加最终结果:
class Book:
def __init__(self, name, author, comment, state = 0):
self.name = name
self.author = author
self.comment = comment
self.state = state
def __str__(self):
status = '未借出'
if self.state == 1:
status = '已借出'
return '名称:《%s》 作者:%s 推荐语:%s\n状态:%s ' % (self.name, self.author, self.comment, status)
class BookManager:
books = []
def __init__(self):
book1 = Book('惶然录','费尔南多·佩索阿','一个迷失方向且濒于崩溃的灵魂的自我启示,一首对默默无闻、失败、智慧、困难和沉默的赞美诗。')
book2 = Book('以箭为翅','简媜','调和空灵文风与禅宗境界,刻画人间之缘起缘灭。像一条柔韧的绳子,情这个字,不知勒痛多少人的心肉。')
book3 = Book('心是孤独的猎手','卡森·麦卡勒斯','我们渴望倾诉,却从未倾听。女孩、黑人、哑巴、醉鬼、鳏夫的孤独形态各异,却从未退场。',1)
self.books.append(book1)
self.books.append(book2)
self.books.append(book3)
def menu(self):
print('欢迎使用流浪图书管理系统,每本沉默的好书都是一座流浪的岛屿,希望你有缘发现并着陆,为精神家园找到一片栖息地。\n')
while True:
print('1.查询所有书籍\n2.添加书籍\n3.借阅书籍\n4.归还书籍\n5.退出系统\n')
choice = int(input('请输入数字选择对应的功能:'))
if choice == 1:
self.show_all_book()
elif choice == 2:
self.add_book()
elif choice == 3:
self.lend_book()
elif choice == 4:
self.return_book()
else:
print('感谢使用!愿你我成为爱书之人,在茫茫书海里相遇。')
break
def show_all_book(self):
print('书籍信息如下:')
for book in self.books:
print(book)
print('')
def add_book(self):
new_name = input('请输入书籍名称:')
new_author = input('请输入作者名称:')
new_comment = input('请输入书籍推荐语:')
new_book = Book(new_name, new_author, new_comment)
self.books.append(new_book)
print('书籍录入成功!\n')
def check_book(self,name):
for book in self.books:
if book.name == name:
return book
else:
return None
def lend_book(self):
name = input('请输入书籍的名称:')
res = self.check_book(name)
if res != None:
if res.state == 1:
print('你来晚了一步,这本书已经被借走了噢')
else:
print('借阅成功,借了不看会变胖噢~')
res.state = 1
else:
print('这本书暂时没有收录在系统里呢')
def return_book(self):
name = input('请输入归还书籍的名称:')
res = self.check_book(name)
if res == None:
print('没有这本书噢,你恐怕输错了书名~')
else:
if res.state == 0:
print('这本书没有被借走,在等待有缘人的垂青呢!')
else:
print('归还成功!')
res.state = 0
manager = BookManager()
manager.menu()
课后练习
在Book类的基础上,创建一个子类FictionBook类代表虚构类图书,并改造初始化方法,增加一个默认参数type = '虚构类'
1.请你在代码的基础上,创建一个【子类】FictionBook。
2.在子类【改造】父类的初始化方法,添加一个虚构类的【属性】,让程序能够打印出实例book的相关信息。
class Book:
def __init__(self, name, author, comment, state = 0):
self.name = name
self.author = author
self.comment = comment
self.state = state
# 创建一个Book类的子类 FictionBook
class FictionBook(Book):
def __init__(self, name, author, comment, state = 0, type = '虚构类'):
Book.__init__(self, name, author, comment, state = 0)
self.type = type
def __str__(self):
status = '未借出'
if self.state == 1:
status = '已借出'
return '类型:%s 名称:《%s》 作者:%s 推荐语:%s\n状态:%s ' % (self.type, self.name, self.author, self.comment, status)
book = FictionBook('囚鸟','冯内古特','我们都是受困于时代的囚鸟')
print(book)
发布者:LJH,转发请注明出处:https://www.ljh.cool/7906.html