湖南大学结对编程个人项目互评
一、简介:
本博客为对结对编程队友的个人项目代码的评价分析
二、代码结构分析:
1.数据变量
由下图可以看出队友使用列表数据类型带表示9位老师的用户名和密码,加减乘除也放在operatorList列表中,还有下方一系列用户操作的变量
import os
import random
import time
personList = [['小学', '张三1', '123'], ['小学', '张三3', '123'], ['小学', '张三3', '123'],
['初中', '李四1', '123'], ['初中', '李四2', '123'], ['初中', '李四3', '123'],
['高中', '王五1', '123'], ['高中', '王五2', '123'], ['高中', '王五3', '123']]
operatorList = ['+', '-', '*', '/']
user_name = '' # 用户名字
level = '' # 题目难度
command = '' # 中间变量,存储命令
question_num = '' # 试卷题目数量
judge = '' # 中间变量,用于满足-1跳出
2.方法函数
这里我们从__main__部分开始看函数,开头直接进入main函数了
if __name__ == '__main__':
main()
下图为main函数部分,在这里队友先调用了login()函数,即登录函数,登录函数在下面分析,之后调用set()函数建立集合,用于存放生成的试卷,接下来调用get_num()函数,提示用户输入题目数量和题目难度,使用全局变量judge表示输入-1则重新登录,接下来获取时间,生成存放试卷的txt文档,读取历史题目文档,使用for循环调用create_question()生成题目,同时进行查重,如果没有重复则加入试卷中,按顺序生成规定数量的题目后,提示用户生成试卷成功
def main():
global judge
while True:
content = ''
judge = False
login()
q_set = set()
get_num()
if judge: # 如果输入-1则重新登录
continue
pre_time = time.strftime("%Y-%m-%d-%H-%M-%S", time.localtime())
pre_path = os.getcwd()
targetpath = pre_path + '/' + user_name + '/' + level # 生成文件目录
# 如果没有文件则创建
if not os.path.exists(targetpath):
os.makedirs(targetpath)
files = os.listdir(targetpath)
# 遍历当前目录下的文件读取历史题目到content
for file in files:
text_path = targetpath + '/' + file
text = open(text_path, 'r', encoding='utf-8')
content += text.read()
# 循环生成题目并查重保存到指定目录
for i in range(int(question_num)):
q_temp = ''.join(create_question())
q_set.add(q_temp)
if len(q_set) == i or (q_temp in content):
i -= 1
continue
f = open('{0}/{1}.txt'.format(targetpath, pre_time), 'a', encoding='utf-8')
f.write('(' + str(i + 1) + ')' + q_temp + '\n' + '\n')
f.close()
print('生成试卷成功,请重新登录')
接下来是login()函数就是将输入的用户名和密码与系统中存放的用户密码进行对比,没有返回值,而是通过修改全局变量来传递参数
def login():
"""实现登录功能
按照输入与列表存储的用户信息匹配判断是否通过登录
Return:
如果输入满足条件则跳出函数执行下一部分
如果输入不满足条件则打印输出请输入用户名和密码
"""
global user_name, level
login_flag = False
print('请输入用户名和密码,两者之间用空格隔开')
while True:
str_user = input().split(' ') # 临时变量,获取当前命令行输入
if len(str_user) != 2:
print('请输入正确的用户名、密码')
continue
inner_name = str_user[0]
inner_password = str_user[1]
# 以下for循环判断输入用户和密码是否匹配
for i in range(len(personList)):
if inner_name == personList[i][1]:
if inner_password == personList[i][2]:
login_flag = True
user_name = inner_name
level = personList[i][0]
if login_flag:
break
else:
print('请输入正确的用户名、密码')
get_num()函数,这里就到了检测用户输入来进行操作了,输入数字10-30就生成题目,输入切换为+学历就切换出题学历,同样,这里的代码没有返回值,就通过全局变量来进行参数的返回判断
def get_num():
"""获取题目数量和题目难度
按照输入获取题目数量和难度等级,输入格式不对则提醒重新输入
Return:
经过函数调用返回当前题目数量和题目难度
"""
global command, question_num, judge, level
while True:
print('准备生成' + level + '数学题目,请输入生成题目数量(输入-1将退出当前用户,重新登录):')
command = input()
if command == '-1':
judge = True
break
# 判断输入是否为纯数或为字符串
if command.isdigit():
question_num = int(command)
if 30 >= question_num >= 10:
break
else:
print('输入范围不符合要求!')
continue
if command == '切换到小学':
level = '小学'
continue
if command == '切换到初中':
level = '初中'
continue
if command == '切换到高中':
level = '高中'
continue
else:
print('请输入小学、初中和高中三个选项中的一个')
continue
下面就是重点creat_question()函数,这里就是按所选的难度生成一个题目
队友生成题目这部分运用了些巧妙的构思,因为小学初中高中的难度是在上一个难度递增的,所以他首先生成数字和加减乘除的简单组合运算,然后判断如果当前难度不等于小学,就添加根号或平方(如果当前难度为初中则保证至少一个根号或平方),如果当前难度为高中,就添加三角函数(保证至少一个三角函数),这样的方式就保证了代码的简洁化
def create_question():
"""生成题目,按所选难度依次逐步生成
按照选取的难度,随机生成操作数和操作符,按梯度生成题目,并将题目存在列表返回
Return:
返回一个列表,列表存储当前生成题目
"""
global level
out_date = []
operand = random.randint(1, 5)
brackets_num = random.randint(0, operand - 1) # 随机括号个数
# 随机生成数值和操作符
for i in range(operand - 1):
out_date.append(str(random.randint(1, 100)))
out_date.append(operatorList[random.randint(0, 3)])
out_date.append(str(random.randint(1, 100)))
out_date.append('=')
# 以下while循环实现加括号,通过brackets_num变量判断括号是否加完
while brackets_num != 0:
choose_before = random.randint(0, len(out_date) - 2)
if out_date[choose_before].isdigit():
out_date.insert(choose_before, '(')
while True:
choose_after = random.randint(choose_before + 1, len(out_date) - 1)
if out_date[choose_after].isdigit():
out_date.insert(choose_after + 1, ')')
brackets_num = brackets_num - 1
break
if level == '小学': # 判断难度是否在此返回
return out_date
gp = 0 # 判断是否加根号或平方
# 以下for循环遍历合理位置随机加根号或平方
for i in range(len(out_date)):
if out_date[i].isdigit() or out_date[i] == '(':
temp = random.randint(0, 1)
if temp == 0:
out_date[i] = '√' + out_date[i]
gp = 1
continue
if out_date[i].isdigit() or out_date[i] == ')':
temp = random.randint(0, 1)
if temp == 1:
out_date[i] = out_date[i] + '^2'
gp = 1
continue
# 以下循环实现若难度为初中且没有加平方或根号则随机加一
while gp != 1 and level == '初中':
i = random.randint(0, len(out_date) - 1)
if out_date[i].isdigit():
temp = random.randint(0, 1)
if temp == 0:
out_date[i] = '√' + out_date[i]
gp = 1
if temp == 1:
out_date[i] = out_date[i] + '^2'
gp = 1
if out_date[i] == ')':
out_date[i] = out_date[i] + '^2'
gp = 1
if out_date[i] == '(':
out_date[i] = '√' + out_date[i]
gp = 1
if level == '初中': # 判断难度是否在此返回
return out_date
gpc = 0 # 判断是否加三角函数运算符
# 以下循环遍历合理位置随机加或不加三角运算符
for i in range(len(out_date)):
if out_date[i].isdigit() or out_date[i] == '(' or out_date[i] == '√':
temps = random.randint(0, 1)
if temps == 1:
temp = random.randint(0, 2)
if temp == 0:
out_date[i] = 'sin' + out_date[i]
if temp == 1:
out_date[i] = 'cos' + out_date[i]
if temp == 2:
out_date[i] = 'tan' + out_date[i]
gpc = 2
# 以下循环实现若一次遍历没有加三角函数操作符则随机位置加一个
while gpc != 2:
i = random.randint(0, len(out_date) - 1)
if out_date[i].isdigit() or out_date[i] == '(' or out_date[i] == '√':
temp = random.randint(0, 2)
if temp == 0:
out_date[i] = 'sin' + out_date[i]
if temp == 1:
out_date[i] = 'cos' + out_date[i]
if temp == 2:
out_date[i] = 'tan' + out_date[i]
gpc = 2
return out_date
三、优缺点分析:
优点:
1.代码简洁,尤其是在生成题目函数部分构思特别巧妙,先生成数字和加减乘除的简单组合也就是小学难度的题,之后检测如果难度不是小学,就随机生成根号和平方,再往下就检测难度如果是高中,就加入三角函数,这样就让代码特别的简洁高效
2.注释简明扼要,不繁复冗长,代码也容易看懂
3.生成题目那里也花了心思,生成的式子中能存在多个括号,同时括号的左右两边可以直接加上根号和平方项,为生成的题目增加了难度
缺点:
1.函数很少使用返回值,很多直接使用全局变量来传递参数,我觉得这是十分危险的做法,不仅在运行代码过程中容易出错,而且非常不适合代码重用
2.封装性较低,没有很好的掌握面向对象的编程思想,面向过程的编程思想较重
3.生成存放试卷的目录就是代码文件目录,生成时有些卡顿,而且没有提示的说
4.小部分变量名使用中文缩写,如pg(平方根号),虽然让代码看起来简洁,但如果后期进入工程的话就可能会带来些许麻烦
四、体会与收获:
这次的个人项目互评让之前没有过这种经历的我收获颇丰,我学到了队友巧妙的编程思想,尤其是生成题目那一块,想到了难度的层层递增这一特点,所以分层编程,让代码十分简洁明了,我一开始有近七百行代码,无从优化,也是由队友启发,最后修正到三百来行。分析原理,巧妙而又简洁的编程思想是之前面向过程编程经验带来的,同时也带来了封装性不够,模块化编程思想缺乏等问题,见贤思齐,见不贤而内自省,在之后的结对项目中,我们都需要取长补短,提高自己面向对象的编程能力,做好函数功能模块化,共同开发出高效,健壮,正确的代码项目。

浙公网安备 33010602011771号