结对编程——个人项目互评
1.简介
本篇文章是对于结对搭档——胡剑锋同学的个人项目的总结评价。胡剑锋同学使用python语言实现了这个中小学生卷子生成系统,总体的层次清楚,细节实现的也比较完善
2.功能要求
用户:小学、初中和高中数学老师。
功能:
1、命令行输入用户名和密码,两者之间用空格隔开
- 如果用户名和密码都正确,将根据账户类型显示“当前选择为XX出题”,XX为小学、初中和高中三个选项中的一个。
- 否则提示“请输入正确的用户名、密码”,重新输入用户名、密码;
2、登录后
- 系统提示“准备生成XX数学题目,请输入生成题目数量(输入-1将退出当前用户,重新登录):”,XX为小学、初中和高中三个选项中的一个,
- 用户输入所需出的卷子的题目数量,系统默认将根据账号类型进行出题。(每道题目的操作数在1-5个之间,操作数取值范围为1-100),题目数量的有效输入范围是“10-30”(含10,30,或-1退出登录)。
3、同一个老师的卷子中的题目不能与以前的已生成的卷子中的题目重复。
4、在登录状态下,如果用户需要切换类型选项,命令行输入“切换为XX”,XX为小学、初中和高中三个选项中的一个
- 输入项不符合要求时,程序控制台提示“请输入小学、初中和高中三个选项中的一个”。
- 输入正确后,显示“”系统提示“准备生成XX数学题目,请输入生成题目数量”,用户输入所需出的卷子的题目数量,系统新设置的类型进行出题;
5、生成的题目将以“年-月-日-时-分-秒.txt”的形式保存,每个账号一个文件夹。每道题目有题号,每题之间空一行;
账户数据表:
账户类型 | 账户 | 密码 |
---|---|---|
小学 | 张三1 | 123 |
张三2 | 123 | |
张三3 | 123 | |
初中 | 李四1 | 123 |
李四2 | 123 | |
李四3 | 123 | |
高中 | 王五1 | 123 |
王五2 | 123 | |
王五3 | 123 |
难度要求:
小学 | 初中 | 高中 | |
---|---|---|---|
难度要求 | +,-,*./ | 平方、开方 | sin,cos,tan |
备注 | 只能有+,-,*./和() | 题目中至少有一个平方或开根号的运算符 | 题目中至少有一个sin,cos或tan的运算符 |
3.代码结构
3.1 代码整体结构
胡同学整体使用了下列的3个类,分别有各自的功能:
class User <- class Teacher
//负责存储账户的基本信息
User--
-
class QuestionMethed <- class QuestionGenerator //负责题目随机生成的主要实现
class System <- class QuestionGenerateSystem
//作为系统的主界面函数
-
胡同学每个类都对应一个抽象基类,有很好的面向对象的编程的思想
-
类之间的功能也是区分的很开,既无遗漏,也无赘余
-
账户的数据通过文档进行保存,具有易修改性,且比较安全
整体的框架设计十分优秀
整体的结构如下:
3.2 代码细节分析
本次的核心代码主要在于生成题目,因此其它地方不做细节分析,重点关注几个核心功能的实现
3.2.1 生成题目
胡剑锋同学成题目采用了如下步骤:
题目将经过生成:
1.操作数数量 2.生成操作数
3.生成括号 4.生成平方(开方)
5.生成三角函数最终生成
实现题目生成顶层的设计:
num_operands = random.randint(2, 5)
self.question = [str(random.randint(1, 100))
for _ in range(num_operands)]
if num_operands > 2:
self.bracket_generate(0, num_operands - 1)
if user.user_type in ['初中', '高中']:
self.square_generate()
if user.user_type == '高中':
self.trigonometric_generate()
self.question = self.operators_generate()
基本与上面所述的步骤一致
下面则为每个具体的实现
bracket_generate:
通过probability实现括号的概率生成,之后通过界定开始与结束的位置,用递归多个括号的合理添加,十分精妙
probability = random.randint(0, 2)
if probability != 0:
return
if begin >= end:
return
begin_rand = random.randint(begin, end-1)
end_rand = random.randint(begin_rand+1, end)
self.question[begin_rand] = '(' + self.question[begin_rand]
self.question[end_rand] = self.question[end_rand] + ')'
if end_rand - begin_rand > 1:
self.bracket_generate(begin_rand, end_rand)
if begin_rand - begin > 1:
self.bracket_generate(begin, begin_rand-1)
if end - end_rand > 1:
self.bracket_generate(end_rand+1, end)
square_generate:
通过随机数实现了不同数量的不同概率,之后直接在字符串上加上符号
trigonometric_generate:
与生成平方类似,只是符号变成了在前面增加
# 添加平方/开方
def square_generate(self):
num_square = random.randint(1, 10)
if num_square > 3:
num_square = 1
square_type = ['^2', '^(1/2)']
while num_square > 0:
pos = random.randint(0, len(self.question) - 1)
self.question[pos] = ('%s%s' % (self.question[pos],
random.choice(square_type)))
num_square -= 1
# 添加三角函数
def trigonometric_generate(self):
num_tri = random.randint(1, 10)
if num_tri > 3:
num_tri = 1
tri_type = ['sin', 'cos', 'tan']
while num_tri > 0:
pos = random.randint(0, len(self.question) - 1)
self.question[pos] = ('(%s%s)' % (random.choice(tri_type),
self.question[pos]))
num_tri -= 1
operators_generate
:加入操作符,并交错添加,实现题目的结构
def operators_generate(self):
operators = ['+', '-', '*', '/']
question = []
for q in self.question:
operator_choice = random.choice(operators)
question.append(q)
question.append(operator_choice)
question.pop()
return question
3.2.2 题目查重
question_check
:通过os模块实现相对文件夹的查询,实现文件流下每个文件逐行读取来进行一一比对,并且还与本轮生成的题目一并保存,足够细致
def question_check(self, user):
for q in self.questions:
if operator.eq("".join(q[1:]), "".join(self.question)):
return False
file_path = '%s\\%s\\' % (os.getcwd(), user.name)
if not os.path.exists(file_path):
return True
for filename in os.listdir(file_path):
with open('%s%s' % (file_path, filename), 'r') as f:
for line in f:
read_question = line[:-1].split('.')
if operator.eq(read_question[-1], "".join(self.question)):
return False
return True
3.2.3 切换账户类型
通过字符串的限定及前后字符串的匹配,轻易实现了切换类型
if (len(order_input) == 5 and
order_input[:3] == '切换为' and
order_input[-2:] in ["小学", "初中", "高中"]):
self.user_login.user_type = order_input[-2:]
4.代码测试
登录测试
登录成功:
登录失败:
生成题目测试
合法范围内生成:
生成的题目在命令行显示:
生成的题目也在文件中同步保存:
范围之外
切换账户类型(难度)
退出账户
经过测试,所有题设要求的功能均正常实现,并无明显bug
5.总结
优点:
-
整体上使用python语言编写,加上胡剑锋同学优秀的设计,整体的代码比较简洁干练,层次分明,扩展性良好
-
整体的功能基本实现,并未发现明显的bug
-
使用文档保存账户的全部数据,比起直接保存在程序中隔离性更好
-
全文基本遵守了Google的python代码规范,命名正确,代码简短,分离性比较强
-
账户在生成题目之后才会生成对应的文件夹,这种按需分配的方式使得整体的文件结构更美观
-
题目的生成比较合理,包括了括号的嵌套,三角函数与平方/开方大概率只有一个,使得生成的题目较为简单
缺点:
-
构建的代码除了整体的注释,对于单行的代码注释较少,导致阅读有些困难
-
最后运行时的命令行的界面不太美观,可以进行改进
-
括号的匹配直接加入字符串,导致后续有些平方的作用范围不可控
-
有些不必要的类也做了抽象,显得有些刻意,不是很符合实际
-
题号与题目之间没有空格,导致容易混淆