使用面向对象编程构建一个Python乘法表应用程序
在本文中,您将使用Python中面向对象编程(OOP)的强大功能来构建一个乘法表应用程序。
您将练习O.O.P的主要概念以及如何在完全功能的应用程序中使用它们。
Python是一种多范式编程语言,这意味着作为开发人员,我们可以根据每个情况和问题选择最佳选项。当我们谈论面向对象编程时,我们指的是在过去几十年里构建可扩展应用程序的最常用范例之一。
OOP的基本知识
我们将快速了解O.O.P在Python中最重要的概念,即类。
类是一个模板,我们可以在其中定义对象的结构和行为。该模板允许我们创建实例,这些实例只是按照类的组成方式制作的各个对象。
一个简单的书籍类,具有标题和颜色属性,可以定义如下。
class Book:
def __init__(self, title, color):
self.title = title
self.color = color
如果我们想要创建类书的实例,我们必须调用类并向其传递参数。
# Book类的实例对象
blue_book = Book("The blue kid", "Blue")
green_book = Book("The frog story", "Green")
我们当前程序的良好表示如下:
太棒了,当我们检查blue_book和green_book实例的类型时,我们得到的是“Book”。
# 打印书籍的类型
print(type(blue_book))
#
print(type(green_book))
#
在弄清楚这些概念之后,我们可以开始构建项目了😃。
项目陈述
当我们作为开发人员/程序员工作时,大部分时间都不是用来编写代码的,根据thenewstack,我们只有三分之一的时间用于编写或重构代码。
我们花费的另外三分之二的时间是阅读其他人的代码和analyzing the problem我们正在处理的内容。
因此,对于这个项目,我将生成一个问题陈述,我们将分析如何从中创建我们的应用程序。结果是,我们将完成整个过程,从思考解决方案到应用代码。
一位小学教师需要一个测试8至10岁学生乘法技能的游戏。
游戏必须有一个生命和得分系统,学生从3个生命开始,必须达到一定的得分才能获胜。如果学生耗尽所有生命,程序必须显示“输”信息。
游戏必须有两种模式,随机乘法和乘法表。
第一种模式应该给学生一个从1到10的随机乘法,他/她必须正确回答才能获得一分。如果这种情况不发生,学生就会失去一条生命并继续游戏。只有当学生达到5分时,他/她才能获胜。
第二种模式必须显示从1到10的乘法表,学生必须输入相应乘法的结果。如果学生连续3次失败,他/她就会输掉游戏,但是如果他/她完成了两张乘法表,游戏就结束了。
我知道需求可能有点多,但我向您保证我们将在本文中解决它们 😁。
分而治之
编程中最重要的技能是解决问题。这是因为您在开始编写代码之前需要有一个计划hacking in the code。
我总是建议将较大的问题分解为可以轻松有效地解决的更小的问题。
所以,如果你需要 create a game,首先要分解成它最重要的部分。这些子问题会更容易解决。
然后你就能清楚地知道如何执行和将所有内容与代码集成。
所以让我们画出游戏的样子。
这张图建立了我们应用程序中对象之间的关系。你可以看到两个主要对象是随机乘法和表格乘法。它们唯一共享的是属性分数和生命。
有了所有这些信息,让我们进入代码。
创建父游戏类
当我们使用面向对象的编程时,我们寻找避免代码重复的最简洁方法。这被称为 DRY(不要重复自己)。
注意:这个目标与编写更少行的代码无关(代码质量不能通过这个方面来衡量),而是抽象出最常用的逻辑。
根据上述思想,我们应用程序的父类必须建立其他两个类的结构和所需行为。
让我们看看如何实现。
class BaseGame:
# 信息居中的长度
message_lenght = 60
description = ""
def __init__(self, points_to_win, n_lives=3):
"""Base game class
Args:
points_to_win (int): 游戏需要达到的分数
n_lives (int): 学生拥有的生命数。默认值为3。
"""
self.points_to_win = points_to_win
self.points = 0
self.lives = n_lives
def get_numeric_input(self, message=""):
while True:
# 获取用户输入
user_input = input(message)
# 如果输入是数字,则返回它
# 如果不是,则打印一条消息并重复
if user_input.isnumeric():
return int(user_input)
else:
print("输入必须是一个数字")
continue
def print_welcome_message(self):
print("PYTHON乘法游戏".center(self.message_lenght))
def print_lose_message(self):
print("抱歉,你失去了所有生命".center(self.message_lenght))
def print_win_message(self):
print(f"恭喜你达到了{self.points}分".center(self.message_lenght))
def print_current_lives(self):
print(f"当前你有{self.lives}条生命n")
def print_current_score(self):
print(f"n你的得分是{self.points}")
def print_description(self):
print("nn" + self.description.center(self.message_lenght) + "n")
# 基本运行方法
def run(self):
self.print_welcome_message()
self.print_description()
哇,这个类看起来相当庞大。让我深入解释一下。
首先,让我们了解类属性和构造函数。
基本上,类属性是在类内部但在构造函数或任何方法之外创建的变量。
而实例属性则是仅在构造函数内部创建的变量。
这两者之间的主要区别是范围。也就是说,类属性既可以从实例对象访问,也可以从类访问。另一方面,实例属性只能从实例对象访问。
游戏 = BaseGame(5)
# 从类中访问游戏消息长度类属性
print(游戏.message_lenght) # 60
# 从类中访问消息长度类属性
print(BaseGame.message_lenght) # 60
# 从实例中访问points实例属性
print(游戏.points) # 0
# 从类中访问points实例属性
print(BaseGame.points) # 属性错误
另一篇文章可以更深入地探讨这个主题。请保持联系以阅读它。
get_numeric_input函数用于防止用户提供非数值输入。正如您可能注意到的,此方法被设计为要求用户直到它获取数值输入为止。我们将在子类中稍后使用它。
print方法允许我们保存在游戏中每次事件发生时都打印相同内容的重复。
最后但并非最不重要的,run方法只是一个包装器,随机乘法和表乘法类将使用它与用户交互并使一切功能正常。
创建子类
一旦我们创建了父类,确定了应用程序的结构和一些功能,就可以使用继承的力量来构建实际的游戏模式类了。
随机乘法类
这个类将运行我们游戏的“第一模式”。当然,它将使用random模块,这将使我们能够向用户询问1到10的随机运算。链接7是关于随机(和其他重要模块)的优秀文章。
import random #用于随机操作的模块
类随机乘法(BaseGame):
描述=“在这个游戏中,您必须正确回答随机乘法n如果您达到5分,您将获胜,如果您失去所有生命,您将失败”
def __init__(self):
#需要获胜的分数是5
#传递5个“points_to_win”参数
super()。__init__(5)
def get_random_numbers(self):
第一个数字= random.randint(1, 10)
第二个数字= random.randint(1, 10)
return first_number,second_number
def run(self):
#调用上层类打印欢迎消息
super()。run()
while self.lives > 0 and self.points_to_win > self.points:
#获取两个随机数字
number1,number2 = self.get_random_numbers()
operation = f“{number1} x {number2}:”
#要求用户回答该操作
#防止值错误
user_answer = self.get_numeric_input(message=operation)
if user_answer == number1 * number2:
print(“n您的答案是正确的n”)
#增加一个点
self.points += 1
else:
print(“n对不起,您的答案是错误的n”)
#减去一个生命
self.lives -= 1
self.print_current_score()
self.print_current_lives()
#仅在游戏完成时执行
#并且没有一个条件为真
else:
#打印最终消息
if self.points >= self.points_to_win:
self.print_win_message()
else:
self.print_lose_message()
这是另一个庞大的类😅。但正如我之前所说,它不是所需的行数,而是可读性和效率。而Python最好的地方在于它允许开发人员编写干净易读的代码,就像他们在用正常英语交谈一样。
这个类有一件事可能会让你困惑,但我会尽可能简单地解释。
# 父类
def __init__(self, points_to_win, n_lives=3):
"...
# 子类
def __init__(self):
# 赢得比赛所需的点数是5
# 传递5个 "points_to_win" 参数
super().__init__(5)
子类的构造函数调用了super函数,同时引用了父类(BaseGame)的类。它基本上告诉Python:
用5来填充父类的“points_to_win”属性!
在self内部不必要放置self,因为我们在构造函数内调用了super,这将导致冗余。
我们还在run方法中使用了super函数,我们将看到在那段代码中发生了什么。
# 基本的run方法
# 父类方法
def run(self):
self.print_welcome_message()
self.print_description()
def run(self):
# 调用上一层类来打印欢迎消息
super().run()
.....
正如你可能注意到的,父类中的run方法打印欢迎和描述消息。但把该功能保留下来,并在子类中添加额外的功能是一个好主意。根据这一点,我们使用super在运行下一段代码之前运行父类方法的所有代码。
run函数的另一部分非常直接。它要求用户输入一个数字,并显示操作的消息。然后将结果与实际乘法进行比较,如果它们相等,则添加一个点,如果不相等,则减去一个生命。
值得一提的是,我们使用了while-else循环。这超出了本文的范围,但我会在几天内发布一篇相关文章。
最后,get_random_numbers使用了random.randint函数,该函数返回指定范围内的随机整数。然后它返回两个随机整数的元组。
随机乘法类
“第二种模式”必须以乘法表格式显示游戏,并确保用户至少正确回答2个表格。
为此,我们将再次使用super的功能,并修改父类属性points_to_win为2。
class TableMultiplication(BaseGame):
description = “在这个游戏中,您必须正确解决完整的乘法表n如果您解决了2个乘法表,您将获胜”
def __init__(self):
# 需要完成2个乘法表才能获胜
super().__init__(2)
def run(self):
# 打印欢迎信息
super().run()
while self.lives > 0 and self.points_to_win > self.points:
# 获取两个随机数
number = random.randint(1, 10)
for i in range(1, 11):
if self.lives = self.points_to_win:
self.print_win_message()
else:
self.print_lose_message()
# 正如您所意识到的,我们只修改了这个类的run方法。这就是继承的魔力所在,我们在多个地方写一次我们使用的逻辑,然后忘记它😅。
# 在run方法中,我们使用了一个循环来获取从1到10的数字,并构建显示给用户的操作。
# 再一次,如果生命用尽或达到了所需的胜利点数,while循环将中断,并显示胜利或失败消息。
# 是的,我们创建了游戏的两种模式,但直到现在,如果我们运行程序,什么都不会发生。
# 因此,让我们通过实现模式选择并根据选择实例化类来完成程序。
# 选择实现
# 用户将能够选择要玩的模式。让我们看看如何实现它。
if __name__ == “__main__”:
print(“选择游戏模式”)
choice = input(“[1],[2]: “)
if choice == “1”:
game = RandomMultiplication()
elif choice == “2”:
game = TableMultiplication()
else:
print(“请选择有效的游戏模式”)
exit()
game.run()
# 首先,我们要求用户在1或2个模式之间进行选择。如果输入无效,则脚本停止运行。如果用户选择了第一种模式,程序将运行”Random Multiplication”游戏模式,如果选择了第二种模式,则运行”Table multiplication”模式。
# 下面是它的外观。
# 贺喜你,你刚刚用面向对象编程完成了一个项目。
# 所有的代码都可以在链接中找到。
# 在本文中,您学会了:
# 使用Python类构造函数
# 使用面向对象的方式创建一个功能性的应用程序
# 在Python类中使用super函数
# 应用继承的基本概念
# 实现类和实例属性
# 祝你编码愉快👨💻
# 接下来,探索一些提高生产力的链接。