这个作业属于哪个课程 | < 2301-计算机学院-软件工程> |
---|---|
这个作业要求在哪里 | < 软工实践第一次作业> |
这个作业的目标 | < 实现一个科学计算器具备的基本功能,并且UI设计较美观 > |
其他参考文献 | < Python_GUI Math库 python2exe> |
- 拿到这个题目本来是准备做一个微信小程序实现计算器,后来了解到不建议使用小程序,又考虑到从头学前端的时间问题,经过在csdn查阅相关资料后,准备使用
Python
的GUI-tkinter
库进行实现。- 初步想法是先进行一个简单计算器的设计,比如加减乘除法,实现一些基本功能,然后在此基础上进行功能的丰富,实现科学计算等功能。
- 又想到自己在使用计算器的时候,对历史记录的查询十分看重,因此想开发一个具有历史记录查询功能的计算器方便用户对自己过去输入过的计算式进行查询。
- 一个计算器,一个软件是否受人欢迎,除了它的功能较为完善以外,其应该有着以一个较为美观的外表,因此UI设计也是相当重要。(实则还有很大进步空间)
Python实现科学计算器并测试
PSP | Personal Software Process Stages | 预估耗时(分钟) | 实际耗时(分钟) |
---|---|---|---|
Planning | 计划 | 20 | 30 |
• Estimate | • 估计这个任务需要多少时间 | 20 | 30 |
Development | 开发 | 490 | 725 |
• Analysis | • 需求分析 (包括学习新技术) | 120 | 100 |
• Design Spec | • 生成设计文档 | 30 | 20 |
• Design Review | • 设计复审 | 20 | 20 |
• Coding Standard | • 代码规范 (为目前的开发制定合适的规范) | 15 | 20 |
• Design | • 具体设计 | 30 | 35 |
• Coding | • 具体编码 | 180 | 260 |
• Code Review | • 代码复审 | 20 | 30 |
• Test | • 测试(自我测试,修改代码,提交修改) | 120 | 240 |
Reporting | 报告 | 190 | 230 |
• Test Repor | • 测试报告 | 120 | 130 |
• Size Measurement | • 计算工作量 | 10 | 10 |
• Postmortem & Process Improvement Plan | • 事后总结, 并提出过程改进计划 | 60 | 90 |
合计 | 700 | 985 |
本次设计科学计算器共用到两个类
class BTN(Button)
和class Calculator
类1 : class BTN(Button)
含义:自定义 按钮类 从tkinter.Button
中继承而来
功能:给按钮设置统一的风格,减少冗余代码
与类2
的关系:Calculator
类用 BTN
类 自定义按钮
代码展示: (仅展示了定义计算器第一行的按钮制作)
class BTN(Button):
# 自定义按钮类,设置显示文本你,显示为位置,以及对应函数
def __init__(self,frame,text,fun, args,bg='white',fg='black'):
super(BTN,self).__init__()
self.x,self.y,self.w,self.h = args[0],args[1],args[2],args[3]
self.btn = Button(frame,text=text,bg=bg,fg=fg,command=fun).place(x=self.x, y=self.y, width=self.w, height=self.h)
# 第一行按钮制作
self.button_cube_root = BTN(self.master, 'X^1/3', fun=lambda: self.getNum('**(1/3)'),args=('10', '150', '60', '40')) # x^(1/3)
self.button_XY = BTN(self.master, 'X^y', fun=lambda: self.getNum('**'),args=('90', '150', '60', '40')) #todo 次方项如何开发 显示 x^
self.button_left = BTN(self.master, '(', fun=lambda: self.getNum('('),args=('170','150','60','40'))
self.button_right = BTN(self.master, ')', fun=lambda: self.getNum(')'),args=('250', '150', '60', '40'))
self.button_c = BTN(self.master, 'C', fun=self.clear,args=('330', '150','60','40'),fg='red')
self.button_back = BTN(self.master, 'Back', fun=self.back, args=('410', '150', '60', '40'))
self.button_division = BTN(self.master, text='÷', fun=lambda: self.getNum('÷'),args=('490', '150', '60', '40'),fg='red')
类 2 : class Calculator
含义: 计算器类,用于计算器初始化
功能: 有10多个功能属性,30+ 个按钮属性,5个计算函数(back
,get_history
,getNum
,clear
,run
)
关键所在:
^
,而计算表达式存**
)def getNum(self, num):
if self.flag: # 用于处理输入=号计算后再输入新的表达式自动情况的功能
self.screen_equation.set('')
self.equation.set('0')
self.result.set('')
self.flag = 0
temp_equ = self.equation.get() # 输入算式
temp_screen_equation = self.screen_equation.get()
if temp_equ == '0' and (num not in ['.', '+', '-', '*', '÷']): #处理算式初始的特殊情况
temp_equ = ''
temp_screen_equation = ''
temp_screen_equation = temp_screen_equation + num
temp_equ = temp_equ + num
self.equation.set(temp_equ)
self.screen_equation.set(temp_screen_equation.replace('**','^').replace('*','x').replace('pi','Π')) # 替换一部分字符,让显示更符号用户渴望看到的
def run(self):
temp_equ = self.equation.get()
self.equ_history.append(temp_equ)
temp_screen = self.screen_equation.get()
self.screen_history.append(temp_screen)
try:
answer = '%.5f' % eval(temp_equ) # 保留两位小数
self.result.set(str(answer))
except (ZeroDivisionError): # 除0错误,语法错误返回Error
self.result.set(str('Error: 除零错误'))
except NameError:
self.result.set(str('Error: 请加上括号'))
except SyntaxError:
self.result.set(str('Error: 语法错误,请正确输入'))
self.res_history.append(self.result.get())
def get_history(self): # 查询历史记录和结果
temp_equ = self.equation.get()
pre_idx = self.equ_history.index(temp_equ)
new_idx = (pre_idx - 1 + len(self.equ_history)) % len(self.equ_history) # 取出上一个计算式子和结果
self.equation.set(self.equ_history[new_idx])
self.result.set(self.res_history[new_idx])
self.screen_equation.set(self.screen_history[new_idx]
sin
,cos
,tan
,log
等多个字符表示的算符需要一次撤销几个字符,需要特殊处理)def back(self):
self.flag = 0 # 设置初始开始标志
temp_equ = self.equation.get()
temp_screen = self.screen_equation.get()
self.screen_equation.set(temp_screen[:-1])
'''
elif temp_equ[-3:] == 'log': # 特殊处理一些复杂算符
self.equation.set(temp_equ[:-3])
self.screen_equation.set(temp_screen[:-3])
elif temp_equ[-3:] == 'sin':
self.equation.set(temp_equ[:-3])
self.screen_equation.set(temp_screen[:-3])
'''
Python2exe
: 可以通过下载Pyinstall
包,在命令对给定的python文件进行转换。具体操作可看 python2exe
单元测试
通过定义了一个测试函数类,和五个测试函数 ,进行计算器的基础算法测试包括(+ - x ÷ )、科学计算(log、ln、x^y、sin、cos、tan等等)
部分代码:
# 测试部分代码 完整代码见github链接
class TestCalculator(unittest.TestCase):
def test_4(self):
Cal = Calculator(root)
Cal.equation.set('sin(pi/2)+cos(pi/2)+tan(pi/4)')
result = Cal.run()
self.assertEqual(result, '2.0')
def test_5(self):
Cal = Calculator(root)
Cal.equation.set('(log10(10**5)-1)/2')
result = Cal.run()
self.assertEqual(result, '2.0')
if __name__ == '__main__':
unittest.main()
性能分析
python的性能分析可以 通过分析函数执行的频繁程度、哪些函数经常阻塞、每个函数的使用时间 以找到性能较低的函数进行优化。(
斯,但是计算器这个好像也没啥特别需要优化性能的)
在使用计算器的时候,难免会有输入错误表达式的时候,因此在这种时候需要及时报错提醒用户,最好有具体的原因!
计算机错误输入分为以下几种:
代码:
try:
answer = '%.5f' % eval(temp_equ) # 保留两位小数
self.result.set(str(answer))
except (ZeroDivisionError): # 其他除0错误,或语法错误返回Error
self.result.set(str('Error: 除零错误'))
except NameError:
self.result.set(str('Error: 请加上括号'))
except SyntaxError:
self.result.set(str('Error: 语法错误,请正确输入'))
Python
的GUI库tkinter
熟悉了其使用,会使用该库进行简单的可视化软件制作.