又是一周结束,为了学习巩固理解个人项目的实践全过程,需要有项目的经验,本周的项目是做一个能自动生成小学四则运算的程序,费时约三个小时,从题目解析到项目构思再到最后成品和测试运算,第一期的项目基本上搭建完成~但是现阶段只能支持二阶运算,后期需要进一步优化将他适用于更加多元的情况中。
一、代码已上传至github我的个人仓库
问题重述:
- 能自动生成小学四则运算题目(注意是给小学生用的,要是结果出现负数的话他们会迷茫的!)
- 除了整数外,还要支持真分数的四则运算
工具列表:
- 编程IDE:Visual Studio Code
- 编程语言:Python
- 效能分析工具:Python自带分析库cProfile
- 源代码托管平台:Github
二、项目PSP:
PSP表格指标 | 预估耗时(分钟) | 实际耗时(分钟) |
计划-估计该任务需要多少时间 | 150 | 154 |
需求分析与思路解析 | 20 | 16 |
代码实现 | 60 | 75 |
代码测试 | 30 | 18 |
代码优化 | 10 | 22 |
写博客 | 30 | 23 |
三、解题思路描述:
在本项目要求中,我们可以清楚明白需求是要编写能够随机生成的四则运算算式,便于小学生计算解题,当然这里面花样可以有很多,例如不仅只是随机数字和随机四则运算符号,还应该可以随机项数,例如可以产生“2*3+6*9-5”这样的5位项的算式,甚至还可以生成带有随机括号的诸如“2*(6+6)/2”的考虑优先级的多样化算式。但考虑到第一次版本,我决定只要编写一个仅有二项的简单的符合题目需求的算式生成代码即可。
考虑到面向对象是小学生,我们的式子不能太过于复杂,算式也不能太“坑爹”。我们首先来看看需要些什么变量?
- 随机整数:rnum (运用Python库中的random库中的randint方法随机生成一个整数)考虑到服务于小学水平,数字不宜过大,且简单四则运算可以为0(需注意除数不能为零即可),故设置范围为0~100
- 随机真分数分子:snum,随机真分数分母:mnum,随机真分数即可表示为Fraction(snum, mnum)(同样运用random库中的randint方法随机生成)
- 随机四则运算符:rsign(通过random.choice(['+','-','*','/']) 来实现)
- 出题数:qes(每次可以出多到题目,qes必须为正整数)
经过理清,我们大致知道我们需要的变量有哪些,接下来分析代码运行过程:
- 从键盘获取计算类型(整数运算?真分数运算?)
- 判断输入是否合法(合法?转3:要求重新输入)
- 从键盘获取出题数qes
- 经过qes此迭代,随机生成对应的随机数和随机运算符,同时筛选出不符合的情况,去掉它
- 计算结果并输出
- 效能分析
四、设计实现过程:
实现类:三个类(除主类)分别为封装函数一:整数求解函数:zsResult();封装函数二:真分数求解函数:zsResult();运算函数:result(s,n1,n2)
其中,zsResult()和zsResult()中都调用运算函数result(s,n1,n2)来进行四则运算,同时result(s,n1,n2)类还负责输出结果
其中,运用random库中的randint方法随机生成整数,用random.choice(['+','-','*','/']) 来实现符号的随机生成,使用max()min()函数防止生成小数
五、代码说明:
关键代码1:运算函数:result(s,n1,n2)
def result(s,n1,n2): if s == '+': print('{} + {} = {}'.format(n1,n2,n1 + n2)) elif s == '-': print('{} - {} = {}'.format(n1,n2,n1 - n2)) elif s == '*': print('{} * {} = {}'.format(n1,n2,n1 * n2)) elif s == '/': if n2 == 0: print('***除数不能为零***') else: print('{} / {} = {}'.format(n1,n2,n1 / n2)) else: print('输入有误,请重新输入!')
关键代码2:整数求解函数:zsResult()
def zsResult(): qes = int(input()) for a in range(qes): rsign = random.choice(['+','-','*','/']) rnum1 = random.randint(0,100) rnum2 = random.randint(0,100) if rnum1 < rnum2: rnum1 = max(rnum1, rnum2) rnum2 = min(rnum1, rnum2) result(rsign,rnum1,rnum2) else: result(rsign,rnum1,rnum2)
关键代码3:真分数求解函数:zsResult()
def zfsResult(): qes = int(input()) for b in range(qes): rsign = random.choice(['+','-','*','/']) snum1 = random.randint(0,100) mnum1 = random.randint(1,100) zfs1 = Fraction(snum1, mnum1) snum2 = random.randint(1,100) mnum2 = random.randint(1,100) zfs2 = Fraction(snum2, mnum2) if zfs1 < zfs2: zfs1 = max(zfs1, zfs2) zfs2 = min(zfs1, zfs2) result(rsign,zfs1,zfs2) else: result(rsign,zfs1,zfs2)
经过以上运算,再编写一个主函数后基本可以实现项目需求~
六、测试运行:
1)整数运算测试:
2)真分数运算测试:
在运算的同时进行效能分析。
3)单元测试:
- 20道题:zsresult()
- 20道题:zfsresult()
- 20道题:result(s,n1,n2)
七、优化改进
经过谨慎思考,我优化了代码层对于需求的适应,扩展了二阶运算为多阶运算,不仅限于简单的两个项的四则运算。
- 优化步骤:
- 分析更高层次需求,得出结论:1)需要多阶运算,不局限于二阶,最好是随机阶数;2)可自主设计出题数和阶数;3)更美观的界面
- 理清思路,分析源程序便于设计
- 更新代码:重新设计重点模块,优化模块调用联系,增加交互界面语句
- 更新github仓库
代码优化展示:
- 函数优化:
1. 关键更新代码1:运算函数:result(s,n1,n2) ---> result(bo,k)
def result(bo,k): #运算函数分类别计算 contain = '' num = 0 rtype = random.randint(2,k) #生成随机项目数 if bo == 1: for i in range(rtype): #生成随机数以及随机运算符 rsign = random.choice(['+','-','*','/']) rnum1 = random.randint(0,100) contain += str(rnum1)+str(rsign) num += 1 if num == rtype: contain = contain[0:-1] + '=' #置换最后一个字符为“=”放在contain字符串中 rescon = contain.replace('=','') #置换最后一个字符为空放在rescon字符串中 if eval(rescon) < 0: #判断结果是否为负数 print('***结果为负数,不显示***') else: print('题目为:{}{}'.format(contain,eval(rescon)))#输出 else: for i in range(rtype): #生成随机真分数以及随机运算符 rsign = random.choice(['+','-','*','/']) snum1 = random.randint(0,100) mnum1 = random.randint(1,100) zfs1 = Fraction(snum1, mnum1) contain += str(zfs1)+str(rsign) num += 1 if num == rtype: contain = contain[0:-1] + '=' rescon = contain.replace('=','') if eval(rescon) < 0: print('***结果为负数,不显示***') else: print('题目为:{}{}'.format(contain,eval(rescon)))#输出
2. 关键更新代码2:整数求解与真分数求解函数:zsResult(),zfsResult()
def zsResult(): #整数运算 print("请输入出题数:") qes = int(input()) print("请输入最大项数:") maxone = int(input()) for a in range(qes): result(1,maxone) #调用实际运算函数result(bo,k) def zfsResult(): #真分数运算 print("请输入出题数:") qes = int(input()) print("请输入最大项数:") maxone = int(input()) for b in range(qes): result(2,maxone) #调用实际运算函数result(bo,k)
- 结果展示
- 整数运算结果:
- 真分数运算结果:
经过优化,项目能够进行不局限于二阶的自主规定范围的随机多阶运算出题了,同时还获得了更加美观的交互界面,得到了一定的性能优化。
八、总结分析:
经过这次个人项目的实践,我初步搭建起可以使用的符合需求的程序,基本上能够运用在实际的小学生简单的四则运算出题过程中,应用范围十分广泛。在这个过程中,我不仅全程进行了项目分析,代码搭建,还进行了多次测试和优化,这是以前所不曾具有的好习惯,我正在慢慢养成,同时以前对于自己的编程比较随意,只是编写就完事了,而今学习了软件工程,我清楚地明白,不仅需要有很好的分析和解决问题的能力,还要有规划和总结的能力,制作PSP表,编写项目文档,更新日志……还有很多东西需要学习,需要去做,原来编程仅仅只是一部分,一个项目的从产生到维护到优化,还有这么多有趣的工作要做呢~