###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项目工作量计算自顶向下计算工时人力和订单大小 python工作量计算器_python四则运算器编写

具体程序设计:

##成员变量 |||| |:--|:--|:--| |成员名|类型|功能| |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)
##运行效果:


python项目工作量计算自顶向下计算工时人力和订单大小 python工作量计算器_后缀表达式_02

##单元测试 《构建之法》第二章中详细提及了好的单元测试的标准。

单元测试应该在最基本的功能/参数上检验程序的正确性。

单元测试必须由最熟悉代码的人来写。

单元测试过后,机器状态保持不变。

单元测试要快。

单元测试应该产生可重复、一致的结果。

独立性-单元测试的运行/通过/失败不依赖于别的测试,可以人为构造数据,以保持测试的独立性。

单元测试应该覆盖所有代码路径。

##效能分析图 Pycharm中运行profiler,次数为10W次

python项目工作量计算自顶向下计算工时人力和订单大小 python工作量计算器_后缀表达式_03

可以看到所用的时间长度为16.04s