结对编程项目互评
此项目用于为中小学生生成数学试卷,下面对我的队友吕斐,以下简称lvfei。做出代码分析,以及说说我的心得体会。
一、队友代码分析
1、primary_test函数分析:
1 def primary_test():
2 """功能为通过随机数,保证每一道小学题目满足四则运算要求,同时可能包含括号。
3 Returns:
4 str1:小学题目的字符串。
5 """
6 operations_num = random.randint(1, 5)
7 operations = ['+', '-', '*', '/']
8 ans = []
9 time1 = 0 # 记录数字
10 time2 = 0 # 记录操作符
11 time3 = 0 # 记录括号个数
12 for _ in range(1, operations_num + 2):
13 nums = random.randint(1, 100)
14 contain = random.randint(0, 1) # 随机加括号
15 k = random.randint(0, 3) # 选取第几个操作符
16 ans.append(nums)
17 time1 += 1
18 if time3 != 0 and contain == 1:
19 ans.append(')')
20 time3 -= 1
21 if time1 + 1 != operations_num + 2:
22 ans.append(operations[k])
23 if contain == 0:
24 ans.append('(')
25 time3 += 1
26 time2 += 1
27 if time3 != 0:
28 while time3 != 0:
29 ans.append(')')
30 time3 -= 1
31 ans = [str(i) for i in ans] # 将题目转换为字符串类型
32 str1 = ''.join(ans)
33 return str1
此函数用于产生小学试卷,这里lvfei很巧秒的构造了括号,由于每一对括号必须成对出现的,lvfei设置了一个contain变量
用来判断某一位数字之后是否应该加上')',同时与之匹配的左括号数量减1,这样匹配到了最后再查看左括号的数量,如果
还有剩余的话统一在右边添加括号,这样就可以让所有括号成对出现了。
2、junior_test函数分析:
1 def junior_test():
2 """功能为通过随机数,保证每一道初中题目都有平方或者sqrt开方。
3
4 Returns:
5 str1:初中题目的字符串。
6 """
7 operations_num = random.randint(1, 5)
8 operations = ['+', '-', '*', '/']
9 ans = []
10 time1 = 0
11 time2 = 0
12 time3 = 0
13 sqrt_and_power = 0 # 保证每道题目至少有一个平方或开方
14 for _ in range(1, operations_num + 2):
15 nums = random.randint(1, 100)
16 contain = random.randint(0, 1) # 随机加括号
17 has_sqrt = random.randint(0, 1) # 随机加根号
18 has_power = random.randint(0, 1) # 随机加平方
19 k = random.randint(0, 3)
20 ans.append(nums)
21 if has_power == 1:
22 ans.append('^2')
23 sqrt_and_power += 1
24 time1 += 1
25 if time3 != 0 and contain == 1:
26 ans.append(')')
27 time3 -= 1
28 if time1 + 1 != operations_num + 2:
29 ans.append(operations[k])
30 if contain == 0:
31 if has_sqrt == 1:
32 ans.append('sqrt')
33 sqrt_and_power += 1
34 ans.append('(')
35 time3 += 1
36 time2 += 1
37 if time3 != 0:
38 while time3 != 0:
39 ans.append(')')
40 time3 -= 1
41 if sqrt_and_power == 0:
42 ans.append('^2')
43 ans = [str(i) for i in ans]
44 str1 = ''.join(ans)
45 return str1
此函数有点类似于上一个生成小学试卷的函数,lvfei的处理方法仍然是遵循括号成对存在的原则,在每个左括号产生的地方
随机添加根号,由于项目要求每一道题目至少含有一个根号和一个平方,lvfei最后也特判了这一点,程序非常严谨。
3、high_test函数分析:
1 def high_test():
2 """功能为通过随机数,保证每一道高中题目都有sin、cos、tan,同时可能包括根号与平方。
3
4 Returns:
5 str1:高中题目的字符串。
6 """
7 operations_num = random.randint(1, 5)
8 operations = ['+', '-', '*', '/']
9 circular = ['sin', 'cos', 'tan']
10 has_circular = 0
11 ans = []
12 time1 = 0
13 time2 = 0
14 time3 = 0
15 circular_num = 0
16 for _ in range(1, operations_num + 2):
17 nums = random.randint(1, 100)
18 contain = random.randint(0, 1) # 随机加括号
19 has_sqrt = random.randint(0, 5) # 随机加根号
20 has_power = random.randint(0, 5) # 随机加平方
21 need_circular = random.randint(0, 2)
22 t = random.randint(0, 2) # 随机选取三角函数
23 k = random.randint(0, 3)
24 if has_circular == 0:
25 ans.append(circular[t])
26 circular_num += 1
27 ans.append('(')
28 ans.append(nums)
29 time3 += 1
30 has_circular = 1
31 else:
32 ans.append(nums)
33 if has_power == 1:
34 ans.append('^2')
35 time1 += 1
36 if time3 != 0 and contain == 1:
37 ans.append(')')
38 time3 -= 1
39 if time1 + 1 != operations_num + 2:
40 ans.append(operations[k])
41 if need_circular == 0:
42 ans.append(circular[t])
43 ans.append('(')
44 time3 += 1
45 if contain == 0:
46 if has_sqrt == 1:
47 ans.append('sqrt')
48 ans.append('(')
49 time3 += 1
50 time2 += 1
51 if time3 != 0:
52 while time3 != 0:
53 ans.append(')')
54 time3 -= 1
55 ans = [str(i) for i in ans]
56 str1 = ''.join(ans)
57 return str1
这里需要产生sin,cos,tan等三角符号,lvfei同样借鉴了小学,初中的代码,做出了复用,在添加左括号的同时随机添加
三角符号,同时增加了平方,根号,也特判了三角符号为空的情况,总的来说他的三个生成题目函数做的很随机,括号的嵌
套,运算符号的随机分布,运算顺序的各种情况均被覆盖。
4、enter函数分析:
1 def enter():
2 """通过输入的用户名和密码进行匹配来判断用户类型以及是否登录成功。
3
4 Input:
5 'enter_account':账户的用户名。
6 'enter_password':账户的密码。
7 Returns:
8 'test_type':通过账号判断的试卷类型。
9 'enter_account':输入的账户名。
10 Raises:
11 ValueError:当输入的数量不等于2报错。
12 """
13 primary_account = ['张三1', '张三2', '张三3']
14 primary_password = ['123', '123', '123']
15 junior_account = ['李四1', '李四2', '李四3']
16 junior_password = ['123', '123', '123']
17 high_account = ['王五1', '王五2', '王五3']
18 high_password = ['123', '123', '123']
19 test_type = 0
20 print("请输入正确的用户名、密码:")
21 enter_account = ''
22 password_is_correct = -1
23 while password_is_correct != 1:
24 try: # 当输入数量过多或过少时try接住
25 enter_account, enter_password = input().split()
26 except ValueError:
27 enter_account = ''
28 enter_password = ''
29 if primary_account.count(enter_account) and password_is_correct != 1:
30 loc = primary_account.index(enter_account)
31 if enter_password == primary_password[loc]:
32 test_type = 1
33 password_is_correct = 1
34 print("当前选择为小学出题")
35 else:
36 password_is_correct = 0
37 if junior_account.count(enter_account) and password_is_correct != 1:
38 loc = junior_account.index(enter_account)
39 if enter_password == junior_password[loc]:
40 test_type = 2
41 password_is_correct = 1
42 print("当前选择为初中出题")
43 else:
44 password_is_correct = 0
45 if high_account.count(enter_account) and password_is_correct != 1:
46 loc = high_account.index(enter_account)
47 if enter_password == high_password[loc]:
48 test_type = 3
49 password_is_correct = 1
50 print("当前选择为高中出题")
51 else:
52 password_is_correct = 0
53 if password_is_correct != 1:
54 print("请重新输入账号密码:")
55 return [test_type, enter_account]
此函数是用户的登录函数,对于输入的部分,lvfei均采用了python里面的try-except模式,保证了当用户输入不合法时不
会报错,而会转而提醒用户输入正确的语句,这部分是我值得学习的,除此之外将enter函数的返回值设定类型加账户能增
强代码的可移植性,当我们需要增加一个用户时只需设定好名称和所属类型即可操作,非常方便。
5、switch函数分析:
1 def switch():
2 """实现用户切换、确定生成题目数量以及生成试卷文件。
3
4 Input:
5 question:题目数量、切换用户命令、重新登录、退出系统。
6 Raises:
7 ValueError:当输入为中文字符串需要将其转换为数字时出错。
8 """
9 answer = enter()
10 test_type = answer[0]
11 enter_account = answer[1]
12 path = os.getcwd() + './' + enter_account # 当前账户的文件夹路径
13 question_num = 0
14 while question_num != -1: # 模式切换
15 if test_type == 1:
16 print("准备生成小学数学题目,请输入生成题目数量(10~30),输入-1将退出当前用户,重新登录,输入-2则退出系统")
17 print("如果需要切换试卷类型,请输入切换为小学、初中或高中")
18 elif test_type == 2:
19 print("准备生成初中数学题目,请输入生成题目数量(10~30),输入-1将退出当前用户,重新登录,输入-2则退出系统")
20 print("如果需要切换试卷类型,请输入切换为小学、初中或高中")
21 else:
22 print("准备生成高中数学题目,请输入生成题目数量(10~30),输入-1将退出当前用户,重新登录,输入-2则退出系统")
23 print("如果需要切换试卷类型,请输入切换为小学、初中或高中")
24 question_num = 0
25 test_num_ok = 0
26 while test_num_ok != 1: # 不断询问切换试卷类型
27 question = input() # 判断输入是否为字符串或者数字,字符串转换为数字的话可能报错,这里用try接一下
28 try:
29 question_num = int(question)
30 except ValueError:
31 question_num = sys.maxsize
32
33 if question_num == sys.maxsize:
34 if question == "切换为小学":
35 test_type = 1
36 elif question == "切换为初中":
37 test_type = 2
38 elif question == "切换为高中":
39 test_type = 3
40 else:
41 print("请输入小学、初中和高中三个选项中的一个")
42 if question_num == -1:
43 switch()
44 elif question_num == -2:
45 print("已退出系统")
46 sys.exit()
47 elif question_num < 10 or question_num > 30 and question_num != sys.maxsize:
48 print("请重新输入生成题目数量(10~30):")
49 else:
50 test_num_ok = 1
51 time.sleep(1.5)
52 if question_num != sys.maxsize: # 判断是否切换,不切换的话就生成题目
53 print("正在生成题目中,请稍后......")
54 date_string = time.strftime(
55 "%Y-%m-%d-%H-%M-%S") # 将实时时间作为文件名
56 if test_type == 1:
57 folder = os.path.exists(path)
58 if not folder:
59 os.mkdir(path)
60 f = open(path + './' + date_string +
61 '.txt', 'w', encoding='UTF-8')
62 problem_sum = 1
63 str_file_data = ''
64 while problem_sum != question_num + 1:
65 problem = str(primary_test())
66 file_list = os.listdir(path)
67 for i in range(0, len(file_list)): # 读取文件夹下所有试卷题目,将其转换为字符串并查重
68 f1 = open(path + './' +
69 file_list[i], 'r', encoding='UTF-8')
70 file_data = f1.readlines()
71 ans = [str(i) for i in file_data]
72 str_file_data = ''.join(ans)
73 if problem not in str_file_data:
74 f.write("第" + str(problem_sum) + "题:" + problem +
75 "=_______." + '\n' + '\n')
76 problem_sum += 1
77 print("试卷已生成完毕!")
78 time.sleep(1)
79 f.close()
80 elif test_type == 2:
81 folder = os.path.exists(path)
82 if not folder:
83 os.mkdir(path)
84 f = open(path + './' + date_string +
85 '.txt', 'w', encoding='UTF-8')
86 problem_sum = 1
87 str_file_data = ''
88 while problem_sum != question_num + 1:
89 problem = str(junior_test())
90 file_list = os.listdir(path)
91 for i in range(0, len(file_list)):
92 f1 = open(path + './' +
93 file_list[i], 'r', encoding='UTF-8')
94 file_data = f1.readlines()
95
96 ans = [str(i) for i in file_data]
97 str_file_data = ''.join(ans)
98 if problem not in str_file_data:
99 f.write("第" + str(problem_sum) + "题:" + problem +
100 "=_______." + '\n' + '\n')
101 problem_sum += 1
102 print("试卷已生成完毕!")
103 time.sleep(1)
104 f.close()
105 else:
106 folder = os.path.exists(path)
107 if not folder:
108 os.mkdir(path)
109 f = open(path + './' + date_string +
110 '.txt', 'w', encoding='UTF-8')
111 problem_sum = 1
112 str_file_data = ''
113 while problem_sum != question_num + 1:
114 problem = str(high_test())
115 file_list = os.listdir(path)
116 for i in range(0, len(file_list)):
117 f1 = open(path + './' +
118 file_list[i], 'r', encoding='UTF-8')
119 file_data = f1.readlines()
120 ans = [str(i) for i in file_data]
121 str_file_data = ''.join(ans)
122 if problem not in str_file_data:
123 f.write("第" + str(problem_sum) + "题:" + problem +
124 "=_______." + '\n' + '\n')
125 problem_sum += 1
126 print("试卷已生成完毕!")
127 time.sleep(1)
128 f.close()
此函数是生成卷子的函数,每次会根据用户类型调用相应的生成题目函数写入文件中,这里我比较关注的是lvfei的查重功能,
但是让我失望的是他的查重功能是不断与之前生成的旧题进行比对,剔除掉不合法的新题,直到生成完所需题目数量,这样子
看起来复杂度过高了,文件IO本身复杂度就很高了,再叠加了一个几乎平方的复杂度,可能当生成题目过多时会很导致时间紧
张,除此之外lvfei比较注意用户体验,在交互界面添加了sleep()函数,使得界面看起来像是机器运作一样。
二、优缺点分析
1、优点
生成题目非常随机化,几乎覆盖了所有的情况。
每一个函数的功能明确,模块化强,可移植性强,可复用性强。
交互功能体验极佳,利用try-except模块避开了输入可能产生了bug。
变量命名规范,几乎达到了看到变量名就知道这个变量用来干什么的地步。
对于字符串的连接都使用了.join函数,而不是简单的'+'。
2、缺点
文件查重功能或许复杂度过高。
没有采用面向对象的思想编程,更多的还是面向过程。
三、我的体会
这次采用的python编程,我们两对于python中的类与对象都不是太熟悉,更多的还是注重了功能的实现,看了lvfei的代码深感自己的
不足,自己变量名用的不是特别规范,函数封装性也不够强,输入的处理也不够细致,但是lvfei同学却考虑到了很多细节,值得我学
习,除此之外,我对python文件操作更加熟练,也了解了更多容器的使用方法,总而言之,我学到了很多!


浙公网安备 33010602011771号