此作业的要求参见[https://edu.cnblogs.com/campus/nenu/2019fall/homework/7631]
代码的git地址[https://e.coding.net/sxl357/f4.git]
git地址下的功能1.py和功能1.exe用来完成功能1,f4.py和f4.exe用来完成功能2和功能3.
功能1. 四则运算
支持出题4个数的四则运算题目,所有题目要求作者有能力正确回答
> f4
1+2*3+4=
?11
答对啦,你真是个天才!
1+2*3+5=
?11
再想想吧,答案似乎是12喔!
1+2/4-5=
?-3.5
答对啦,你真是个天才!
...(一共20道题)
你一共答对4道题,共20道题。
重难点:
1.给定一个运算式,如何让计算机算出结果?
给定的运算式属于中缀表达式,将其改为后缀表达式,再计算结果。
(1)中缀转后缀
#将中缀表达式转为后缀表达式 def make_Expression(s): operations=[] result='' front={'+':1,'-':1,'*':2,'/':2} for i in s: if i in ['+','-','*','/']:#判断是否是操作符 if len(operations)==0:#栈空,直接入栈 operations.append(i) elif front[operations[-1]]>=front[i]:#判断栈顶元素和操作符的优先级别 while len(operations)>0 and front[operations[-1]]>=front[i]:#持续将栈顶元素弹出并输出,直至遇到低于或等于此操作符的优先级别 p=operations.pop() result+=p operations.append(i) else: operations.append(i) else: result+=i#若是数,直接输出 while len(operations)>0:#将栈中的所有元素依次弹出 p=operations.pop() result+=p return result#返回后缀表达式
(2)计算后缀表达式
#计算后缀表达式 def make_Value(s): lists=[] for i in s: if i in ['+','-','*','/']: b=float(lists.pop())#先弹出的是b,下个弹出的是a a=float(lists.pop()) c=0 if i=='+':#判断做哪则运算 c=a+b elif i=='-': c=a-b elif i=='*': c=a*b else: c=a/b lists.append(c)#得到的结果压入栈中 else: lists.append(i) return lists[0]
2.如何随机生成运算式(3个运算符,4个操作数)?
这对于我们来说是个大问题,查资料,询问 师哥师姐,了解到random.randint(a,b)用于生成一个指定范围内的整数n
#随机生成运算式 from random import randint #random.randint(a,b)用于生成一个指定范围内的整数n,其中a<=n<=b # 定义类 class Expression: # 生成运算式 def expre(self):#在类里定义函数必须传入self,指的是类实例对象本身 exp = [] for j in range(0,7): #range(a)=[0,1,2,3,...,a-1] if j % 2 != 0:#通过模2,生成带3个运算符4个10以内数字的表达式 operators = ['+', '-', '*', '/'] exp.append(operators[randint(0, len(operators) - 1)]) #随机生成运算符 else: exp.append(str(randint(1, 9))) #随机生成操作数 expression = ''.join(exp) return expression
generate=Expression() #定义对象 expression = generate.expre()#调用generate()函数,生成运算式
3.如何循环出题,并验算结果,给出反馈?
先生成运算式,然后调用转后缀,计算后缀的函数 ,得到正确结果,与用户输入的对比,给出反馈,循环20次,并利用全局变量累积答对的题的数目。
#出20道考题,判断用户结果是否等于正确答案,实现功能一 def question(): num = 0 global correctNumber # 定义全局变量,统计答对的次数 while num <20: generate=Expression() #定义对象 expression = generate.expre()#调用generate()函数,生成运算式 print(expression + "=") expression1 = make_Expression(expression) # 将中缀表达式转换为后缀表达式 result = make_Value(expression1) # 计算后缀表达式的值 userAnswer = input() # 输入你的答案 if '?' in userAnswer: userAnswer = userAnswer.replace('?', '')#str.replace(old,new,max)方法,把字符中的old替换成new,且替换不超过max次 if (float(userAnswer) == float(result)): # 判断用户结果是否和正确答案相等 correctNumber += 1 print("答对了,你真是个天才!") else: result = str(result) print('再想想吧,答案似乎是' + result + '喔!') num += 1 correctNumber = str(correctNumber) print("你一共答对" + correctNumber + "道题,共20道题。")
4.如何定义此时的主函数?
#定义主函数 def main(argv): question()#实现功能一 #主函数 if __name__ == "__main__": main(sys.argv[1:])
运行测试截图
功能2 支持括号
> f4
1+2*(3+4)=
?15
答对啦,你真是个天才!
(1+2)*3+5=
?11
再想想吧,答案似乎是14喔!
((1/2)-4)*5=
?-17.5
答对啦,你真是个天才!
...(一共20道题)
你一共答对4道题,共20道题。
重难点
1.中缀转后缀时,有括号怎么办?
左括号可以直接入栈,但遇到右括号时,遇到右括号,持续将栈顶元素弹出并输出,直至遇到左括号
for i in s: if i in ['+','-','*','/','(',')']:#判断是否是操作符 if i=='(':#遇到左括号,将其直接放入栈中 operations.append(i) elif i==')':#遇到右括号,持续将栈顶元素弹出并输出,直至遇到左括号 while (len(operations)>0 and operations[-1]!='(' ):#-1表示列表的最后一个元素,即栈顶 p=operations.pop() result+=p operations.pop()#左括号只弹出不输出 elif len(operations)==0:#栈空,直接入栈 operations.append(i) elif front[operations[-1]]>=front[i]:#判断栈顶元素和操作符的优先级别 while len(operations)>0 and front[operations[-1]]>=front[i]:#持续将栈顶元素弹出并输出,直至遇到低于或等于此操作符的优先级别 p=operations.pop() result+=p operations.append(i) else: operations.append(i) else: result+=i#若是数,直接输出
2.何时何地生成括号?
在生成运算式的类中,生成了不带括号的运算式后,随机生成0或1,0就表示不插入括号,1表示插入括号,此时调用生成括号的函数,在该函数中,用枚举法确定括号的位置,然后根据随机数选择其中一种,将括号插入,最后返回带括号的表达式。
is_need_brackets = randint(0, 1) # 判断是否要括号 if is_need_brackets:#添加括号 expression = ''.join(self.make_brackets(exp))#.join()将序列中的元素以指定的字符连接生成一个新的字符串 #加括号时,调用生成括号表达式的函数,得到一个带括号的运算式 else:#不添加括号 expression = ''.join(exp)
# 生成括号表达式 def make_brackets(self,exp):#传入由运算符和数字组成的列表 expression = [] # 可能有一对括号,也可能有两对括号,所以最多有11个位置可以添加括号 #经过枚举,共有10种可能的添加方式 # 0表示直接将运算符或数字传入生成式,1表示在生成式加入左括号,2表示在生成式加入右括号,-1表示不作任何处理 judge_position= [ [1, 0, 0, 0, 2, 0, 0, 0, 0, -1, -1], [1, 0, 0, 0, 0, 0, 2, 0, 0, -1, -1], [0, 0, 1, 0, 0, 0, 2, 0, 0, -1, -1], [0, 0, 1, 0, 0, 0, 0, 0, 2, -1, -1], [0, 0, 0, 0, 1, 0, 0, 0, 2, -1, -1], [1, 0, 0, 0, 2, 0, 1, 0, 0, 0, 2], [1, 1, 0, 0, 0, 2, 0, 0, 2, 0, 0], [1, 0, 0, 1, 0, 0, 0, 2, 2, 0, 0], [0, 0, 1, 1, 0, 0, 0, 2, 0, 0, 2], [0, 0, 1, 0, 0, 1, 0, 0, 0, 2, 2] ] position = randint(0,9) if exp: i = 0 for j in judge_position[position]:#调用上述列表 if j ==0: expression.append(exp[i]) if i < len(exp): i += 1 elif j ==1: expression.append('(') elif j ==2: expression.append(')') return expression
运行测试截图
功能3 限定题目数量,"精美"打印输出,避免重复
>f4 -c 3
1+2*(3+4)= 15
(1+2)*3+5= 14
((1/2)-4)*5= 17.5
>f4 -c -200
题目数量必须是 正整数。
>f4 -c 3.5
题目数量必须是 正整数。
>f4 -c test
题目数量必须是 正整数。
重难点
1.如何规范化输出?
print('%-15s %-15s' % (expression, result)) # 规范输出格式
2.循环体
# 答案与题目横向对齐,使输出规范化,实现功能三 def normal(num): i = 0 while i < num: generate = Expression() expression = generate.expre() expression1 = make_Expression(expression) # 将中缀表达式转换为后缀表达式 result = make_Value(expression1) # 计算后缀表达式的值 expression=expression+"=" print('%-15s %-15s' % (expression, result)) # 规范输出格式 i += 1
3.如何与功能2区分?
在主函数中判断‘-c’是否在输入的命令行参数里,在则功能3,否则功能2.
4.如何在输入的命令行参数是负数或者小数时报错?
count=float(sys.argv[2]) # 获取生成题目的个数 if count >=1: normal(count)
5.主函数
#定义主函数 def main(argv): if '-c' in sys.argv: # 实现功能三 count=float(sys.argv[2]) # 获取生成题目的个数 if count >=1: normal(count) else: print("题目数量必须是正整数。") else: question()#实现功能一二 #主函数 if __name__ == "__main__": main(sys.argv[1:])
运行测试截图
总结
完成这个作业真的是花了很多功夫,因为自己的无知,很多时间都是在做无效的工作,但通过这次学习,我更加清楚了自己的弱势所在,更明白了该怎么去学习,谢谢前面人的工作,使我的学习有迹可循,在此特别感谢我的结对小伙伴梁梦瑶,能在我无比焦躁时安慰我的情绪,和我一起学习,一起努力。