软工第五次作业——Python效能分析之四则运算生成器
Github项目地址:
https://github.com/JtvDeemo/elementary-arithmetic
PSP
| PSP2.1 | Personal Software Process Stages | 预估耗时(分钟) | 实际耗时(分钟) |
| Planning | 计划 | 10 | 10 |
| · Estimate | · 估计这个任务需要多少时间 | 1440 | 920 |
| Development | 开发 | 700 | 200 |
| · Analysis | · 需求分析 (包括学习新技术) | 180 | 240 |
| · Design Spec | · 生成设计文档 | 5 | 5 |
| · Design Review | · 设计复审 (和同事审核设计文档) | 10 | 15 |
| · Coding Standard | · 代码规范 (为目前的开发制定合适的规范) | 5 | 5 |
| · Design | · 具体设计 | 40 | 60 |
| · Coding | · 具体编码 | 300 | 380 |
| · Code Review | · 代码复审 | 30 | 30 |
| · Test | · 测试(自我测试,修改代码,提交修改) | 30 | 30 |
| Reporting | 报告 | 120 | 120 |
| · Test Report | · 测试报告+博客 | 120 | 120 |
| · Size Measurement | · 计算工作量 | 10 | 10 |
| · Postmortem & Process Improvement Plan | · 事后总结, 并提出过程改进计划 | 40 | 50 |
| 合计 | 3040 | 2195 |
题目要求:
- 能自动生成小学四则运算题目
- 除了整数外,还要支持真分数的四则运算
除了以上的基本需求,还有 - 生成的算式长度随机
- 能处理分数的运算,结果能用分数(字符串类型)表示出来,能与用户输入相对应
解题思路:
- 定义一个函数用于随机生成随机长度的算式
- 把字符串型的算式转换为逆波兰式(RPN,也称后缀表达式)
- 再把后缀表达式利用栈结构计算出结果
- 最后再与用户的输入做比较
重点难点:
- 分数的表示与计算
- 后缀表达式的生成和计算
- 结果为负数的情况
如何解决:
- Python的分数计算可以用 fractions 库
- https://blog.csdn.net/qq_36763635/article/details/72627601 这里介绍了如何将中缀表达式转换为后缀表达式(RPN)
- https://blog.csdn.net/yangquanhui1991/article/details/52187375 图解后缀表达式的计算过程
- 对于结果为负数的情况,只能生成算式之后验算一遍,若为负数的情况,重新生成一遍(可能是个人水平有限)
设计实现:

具体程序设计:
成员变量
| 成员名 | 类型 | 功能 |
| op | list | 存放运算符 |
| quest | str | 存放算式 |
| lens | int | 2到9的随机长度 |
| teop | str | 存放当前运算符 |
| tstr | str | 存放当前算式 |
| tint | int | 存放当前运算数 |
成员函数
| 函数名 | 输入 | 输出 | 依赖函数 | 功能 |
| get_string | 冇 | 字符串 | 冇 | 随机生成一个算式 |
| get_ans | str | 返回布尔类型 | get_string | 将用户输入与正确答案比较 |
| to_rpn | str | 返回后缀表达式 | get_ans | 将随机生成的算式转换为RPN |
| this_bigger | str,str | 返回布尔表达式 | 冇啊 | 比较两个运算符的优先级 |
| slove_rpn | str | 返回计算结果 | get_ans | 将后缀表达式计算出来 |
核心代码:
#随机生成一个算式
def get_string(self):
self.lens = random.randint(2, 9)
self.teop = ''
self.tstr = []
for i in range(self.lens):
if self.teop == '÷':
self.tint = random.randint(1, 8)
self.teop = random.choice(self.op)
elif self.teop == '/':
self.tint = random.randint(self.tint+1, 9)
self.teop = random.choice(self.op[:-1])
else:
self.tint = random.randint(0, 8)
self.teop = random.choice(self.op)
self.tstr.append(str(self.tint))
self.tstr.append(self.teop)
self.tstr[-1] = '='
self.tstr = ''.join(self.tstr)
self.quest = self.tstr
return self.tstr
#将随机生成的算式转换为RPN
def to_rpn(self, ques): #Reverse Polish notation
self.stack = []
s = ''
for x in ques:
if x != '+' and x != '-' and x != '×' and x != '÷' and x != '/':
s += x #若为数字,直接输出
else: # 若为运算符,进栈
if not self.stack: #栈空
self.stack.append(x)
else:
if self.this_bigger(x, self.stack[-1]): #运算级高于栈顶元素
self.stack.append(x) #直接进栈
else:
while self.stack:
if self.this_bigger(x, self.stack[-1]):
break
s += self.stack.pop()
self.stack.append(x)
while self.stack:
s += self.stack.pop()
# print('在to_rpn函数中,rpn:',s)
return s
#将后缀表达式计算出来
def slove_rpn(self, rpn):
#print('进入slove_rpn函数:')
self.stack1 = [] #用于保存运算数
for x in rpn:
if x != '+' and x != '-' and x != '×' and x != '÷' and x != '/':
self.stack1.append(int(x))
elif x == '+':
second = self.stack1.pop()
first = self.stack1.pop()
self.stack1.append(first + second)
elif x == '-':
second = self.stack1.pop()
first = self.stack1.pop()
self.stack1.append(first - second)
elif x == '×':
second = self.stack1.pop()
first = self.stack1.pop()
self.stack1.append(first * second)
elif x == '÷':
second = self.stack1.pop()
first = self.stack1.pop()
self.stack1.append(Fraction(first, second))
elif x == '/':
second = self.stack1.pop()
first = self.stack1.pop()
self.stack1.append(Fraction(first, second))
resault = self.stack1[0]
if resault >= 0:
#print('--------------题结束----------------')
return resault
elif resault < 0:
s = self.get_string()
rpn = self.to_rpn(s[:-1])
return self.slove_rpn(rpn)
运行效果:

单元测试
《构建之法》第二章中详细提及了好的单元测试的标准。
- 单元测试应该在最基本的功能/参数上检验程序的正确性。
- 单元测试必须由最熟悉代码的人来写。
- 单元测试过后,机器状态保持不变。
- 单元测试要快。
- 单元测试应该产生可重复、一致的结果。
- 独立性-单元测试的运行/通过/失败不依赖于别的测试,可以人为构造数据,以保持测试的独立性。
- 单元测试应该覆盖所有代码路径。
效能分析图
Pycharm中运行profiler,次数为10W次

可以看到所用的时间长度为16.04s
软工第五次作业——Python效能分析之四则运算生成器的更多相关文章
- 第五次作业——python效能分析与几个问题(个人作业)
第五次作业--效能分析与几个问题(个人作业) 前言 阅读了大家对于本课程的目标和规划之后,想必很多同学都跃跃欲试,迫不及待想要提高自身实践能力,那么就从第一个个人项目开始吧,题目要求见下. 阅读 阅读 ...
- FZU软工第五次作业-词组频率分析
目录 00.前言: 01.分工: 02.PSP表格: 03.解题思路描述与设计实现说明: 解题思路简述: 关键代码 04.附加题设计与展示: 设计的创意独到之处 实现思路 实现成果展示 05.关键代码 ...
- 2020BUAA软工个人博客作业-软件案例分析
2020BUAA软工个人博客作业-软件案例分析 17373010 杜博玮 项目 内容 这个作业属于哪个课程 2020春季计算机学院软件工程(罗杰 任健) 这个作业的要求在哪里 个人博客作业-软件案例分 ...
- FZU软工第十一次作业-软件产品案例分析
目录 前言: 第一部分.调研,评测: 1.1.初次感觉: 1.2.企业号bug: 1.3.你觉得为什么这个产品组的人没有发现这些bug: 1.4.假设你们团队需要开发这套系统,需要注意哪些方面: 2. ...
- 福大软工 · 第十一次作业 - Alpha 事后诸葛亮(团队)
福大软工·第十一次作业-Alpha事后诸葛亮 组长博客链接 本次作业博客链接 项目Postmortem 模板 设想和目标 我们的软件要解决什么问题?是否定义得很清楚?是否对典型用户和典型场景有清晰的描 ...
- 福大软工·第十一次作业-Alpha事后诸葛亮
福大软工·第十一次作业-Alpha事后诸葛亮 组长博客链接 本次作业博客链接 项目Postmortem 模板 设想和目标 我们的软件要解决什么问题?是否定义得很清楚?是否对典型用户和典型场景有清晰的描 ...
- 软工网络15个人作业4——alpha阶段个人总结
软工网络15个人作业4--alpha阶段个人总结 一.个人总结 用自我评价表:http://www.cnblogs.com/xinz/p/3852177.html 总结Alpha冲刺过程. 由于直接用 ...
- 软工 · 第十一次作业 - Alpha 事后诸葛亮(团队)
软工 · 第十一次作业 - Alpha 事后诸葛亮(团队) 组长本次作业链接 现代软件工程 项目Postmortem 设想和目标 1.我们的软件要解决什么问题?是否定义得很清楚?是否对典型用户和典型场 ...
- 【软工】个人项目作业——个人软件流程(PSP)
[软工]个人项目作业--个人软件流程(PSP) 项目 内容 班级:北航2020春软件工程 006班(罗杰.任健 周五) 博客园班级博客 作业:设计程序求几何对象的交点集合 个人项目作业 个人课程目标 ...
随机推荐
- C语言实现万年历
给出你想知道的年份,便可以计算出该年对应的每个月每个日所对应的星期数,是不是感觉很好玩 ? #include <stdio.h> #include<stdlib.h> long ...
- 阿里云服务器实战(二): Linux MySql5.6数据库乱码问题
在阿里云上了买了一个云服务器, 部署了一个程序,发现插入数据库后乱码了,都成了'????'. 一开始怀疑是Tomcat7的原因 , 见文章 : http://blog.csdn.net/johnny ...
- 如何设计一个web容器
开发一个web容器涉及很多不同方面不同层面的技术,例如通信层的知识,程序语言层面的知识等等,且一个可用的web容器是一个比较庞大的系统,要说清楚需要很长的篇幅,本文旨在介绍如何设计一个web容器,只探 ...
- Linux管道编程实例
/*管道 可以把管道想象为两个实体之间的单向连接器.注意,管道是半双工的, 如果需要全双工通讯,应该转而考虑套接字. 匿名管道又称管道,提供了一个进程与它的兄弟进程通讯的方法,只存在于父进程中: 命名 ...
- android重启代码
首先新建一个app然后添加 android:sharedUserId="android.uid.system" 再添加重启的权限 <uses-permission andro ...
- Understanding Android Security(安卓安全的理解)
论文作者: Enck, William Ongtang, MacHigar McDaniel, Patrick 下一代的开放操作系统不会在个人主机和大型主机上出现,而是在只能手机上.新环境的开放性将会 ...
- Linux中find的使用(转)
本文转自:迷途花开 另一值得参考的是吴秦先生的博文linux中强大且常用命令:find.grep. find命令用于查找文件和目录,任何位于参数之前的字符串都将被视为欲查找的目录. find 可以指定 ...
- 数据包接收系列 — IP协议处理流程(一)
本文主要内容:在接收数据包时,IP协议的处理流程. 内核版本:2.6.37 Author:zhangskd @ csdn blog IP报头 IP报头: struct iphdr { #if defi ...
- obj-c编程05:类的多态与id动态绑定
说实在的,写这第5篇的时候十分纠结,代码老是不能动态绑定,在编译时就会出错,最后发现这是开了ARC的原因.开了ARC obj-c就不能动态绑定了吗?这个问题还不清楚哦.把ARC关闭后,虽然会有警告,但 ...
- C# 将PDF转为SVG的3种情况
PDF格式的文档广泛用于各种办公场所,在工作中难免会有将PDF文档转换为其他文档格式的需要.在本篇文档中,将介绍PDF转为SVG的方法.根据不同的转换需求,这里分三种情况进行讲述,即转PDF所有页为S ...