python编写计算器

  1. 1 背景
  2. 2 设计思路
  3. 3 开发环境配置
  4. 4 运行使用方法
  5. 5 运行效果截屏
  6. 6 运行效果分析总结
    1. 6.1 缺陷
    2. 6.2 改进方法
  7. 7 源代码
  8. 8 参考文章

1 背景

大三了,朱老师说如果想不上python前半部分的语法课程,需要做出来点东西让他看看,思虑再三,我选择了计算器这个应用,个人感觉可能稍微好做一点吧(#^.^#)(#^.^#)

2 设计思路

程序的流程图如图1所示,首先利用tkinter模块创建窗口并初始化界面,然后再窗口中添加控件并进行合理的布局,此外,还得实现对应按钮的回调函数的功能,最后,让窗口不停的循环,使其处于一直显示的效果,这样,GUI界面的配置就完成了。

另外,就是输入运算式的处理过程了。首先,我们通过鼠标点击对应按钮显示出运算式,然后将运算式的内容存储在格式化列表中,接着先计算乘除,后计算加减,最后,就可以输出运算结果了。此外,我们还可以通过点击按钮Mc实现清零操作和Mr实现调出上次运算的结果。

图1 计算器流程图

3 开发环境配置

在pycharm2019版中,我进行代码的编辑和审计。在运行过程中,我还安装了python代码的模块re,模块re(Regular Expression正则表达式)可以实现提供各种正则表达式的匹配操作,在文本解析、复杂字符串分析和信息提取时是一个非常有用的工具,安装过程如图2所示。

图2 python模块re的安装

4 运行使用方法

为了演示方便,我分别在Windows 10和Linux(Kali)的命令行中进行演示,最终发现除了运行界面的图标有些许差异,效果相同。

5 运行效果截屏

在Windows10的命令行下,输入python3 demo.py运行程序,效果如图3所示。

图3 windows下的计算功能

点击按钮Mc即可实现清零操作,效果如图4所示。

图4 清零

点击按钮Mr实现调出上一次的运算结果,效果如图5所示。

图5 调出上次的运算结果

在Linux(Kali)的命令行下,输入python3 demo.py运行程序,效果如图6所示。

图6 Linux下的计算功能

点击按钮Mc即可实现清零操作,效果如图7所示。

图7 清零

点击按钮Mr实现调出上一次的运算结果,效果如图8所示。

图8 调出上次的运算结果

6 运行效果分析总结

6.1 缺陷

为了方便显示,我就利用python的tkinter模块来做成了GUI界面,而且只能用鼠标点击对应按钮进行算式运算,因为自己没有学习过基于Windows或者Linux平台上的软件开发,所以就没有进一步将其做成可执行程序。
开发过程中的程序算法还有一定的缺陷,就是不能计算两个负数向乘或者向除的结果,例如(-2)/(-5)或者(-2)*(-5)
类似的运算,win10执行结果如图9所示。

图9 错误界面

6.2 改进方法

经过调试后,我发现原来出现错误的代码是由于两个负数-2和-3相乘后,结果列表的存储为[‘+’,’6’],而sum = float(eq[0])试图将列表中的’+’转化为浮点数,结果爆出错误ValueError: could not convert string to float: ‘+’,如果将判断条件改为if eq[0] != ‘-‘ and eq[0] != ‘+’:就可以避免列表的第一项为’+’而导致强制类型转换错误的存在,改进后可以运算两个负数相乘的结果,改进后的效果如图10所示。

图10 错误界面改进

7 源代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
#!/usr/bin/python
#coding: utf-8
#Filename: calculator_GUI.py
#author:邢帅坤

import tkinter as TK
import re

def change(eq,count):
'''
:param eq: 刚去完括号或者乘除后的格式化列表
:param count: 发生变化的元素的索引
:return: 返回一个不存在 '+-' ,'--'类的格式化列表
'''
if eq[count] == '-':
if eq[count-1] == '-':
eq[count-1] = '+'
del eq[count]
elif eq[count-1] == '+':
eq[count-1] = '-'
del eq[count]
return eq

def remove_multiplication_division(eq):
'''
:param eq: 带有乘除号的格式化列表
:return: 去除了乘除号的格式化列表
'''
count = 0
for i in eq:
if i == '*':
if eq[count+1] != '-':
eq[count-1] = float(eq[count-1]) * float(eq[count+1])
del(eq[count])
del(eq[count])
elif eq[count+1] == '-':
eq[count] = float(eq[count-1]) * float(eq[count+2])
eq[count-1] = '-'
del(eq[count+1])
del(eq[count+1])
eq = change(eq,count-1)
return remove_multiplication_division(eq)
elif i == '/':
if eq[count+1] != '-':
eq[count-1] = float(eq[count-1]) / float(eq[count+1])
del(eq[count])
del(eq[count])
elif eq[count+1] == '-':
eq[count] = float(eq[count-1]) / float(eq[count+2])
eq[count-1] = '-'
del(eq[count+1])
del(eq[count+1])
eq = change(eq,count-1)
return remove_multiplication_division(eq)
count = count + 1
return eq

def remove_plus_minus(eq):
'''
:param eq: 只带有加减号的格式化列表
:return: 计算出整个列表的结果
'''
count = 0
if eq[0] != '-' and eq[0] != '+':
sum = float(eq[0])
else:
sum = 0.0
for i in eq:
if i == '-':
sum = sum - float(eq[count+1])
elif i == '+':
sum = sum + float(eq[count+1])
count = count + 1
if sum >= 0:
eq = [str(sum)]
else:
eq = ['-',str(-sum)]
return eq

def calculate(s_eq):
'''
:param s_eq: 不带括号的格式化列表
:return: 计算结果
'''
if '*' or '/' in s_eq:
s_eq = remove_multiplication_division(s_eq)
if '+' or '-' in s_eq:
s_eq = remove_plus_minus(s_eq)
return s_eq

def simplify(format_list):
'''
:param format_list: 输入的算式格式化列表如['60','+','7','*','8']
:return: 通过递归去括号,返回简化后的列表
'''

bracket = 0 # 用于存放左括号在格式化列表中的索引
count = 0
for i in format_list:
if i == '(':
bracket = count
elif i == ')':
temp = format_list[bracket + 1 : count]
new_temp = calculate(temp)
format_list = format_list[:bracket] + new_temp + format_list[count+1:]
format_list = change(format_list,bracket) # 解决去括号后会出现的-- +- 问题
return simplify(format_list) # 递归去括号
count = count + 1
return format_list # 当递归到最后一层的时候,不再有括号,因此返回列表

def caculator(eq):
format_list = eq_format(eq)
s_eq = simplify(format_list)
ans = calculate(s_eq)
if len(ans) == 2:
ans = -float(ans[1])
else:
ans = float(ans[0])
return ans

# 获得按下的数字或者符号
def getnum(num):
temp = equation.get()
temp2 = result.get()
print(temp)
print(temp2)
if temp2 != ' ':
temp = '0'
temp2 = ' '
result.set(temp2)
if (temp=='0'):
temp = ''
temp = temp + num
equation.set(temp)
print(equation)

# 按下Mc键时,去除最后一个字符
def clear():
equation.set('0')
result.set('0')

# 按下Mr时,调出上次运算的结果
def get_last_result():
equation.set(last_result)
result.set(0)

# 按下等于号时计算结果
def run():
global last_result
temp = equation.get()
temp = temp.replace('x','*')
temp = temp.replace('÷','/')
print(temp)
answer = caculator(temp)
answer = '%.2f'%answer
result.set(str(answer))
last_result = answer

def eq_format(eq):
'''
:param eq: 输入的算式字符串
:return: 格式化以后的列表,如['60','+','7','*','8']
'''
format_list = re.findall('[\d\.]+|\(|\+|\-|\*|\/|\)',eq)
return format_list

# 主窗口
root = TK.Tk() # 创建TK实例
root.title("邢帅坤的计算器") # 设置窗口的显示名字
root.resizable(0,0) # 设置主窗口的宽度和高度是否可以通过鼠标进行拉伸改变,此处设置为不能
root.geometry('320x420') # 这里设置主窗口的初始尺寸,因为我们在上面设定了主窗口大小 不可变,因此这个尺寸也就是主窗口一直不变的尺寸了

result = TK.StringVar() # 用来显示结果的可变文本
equation = TK.StringVar() # 用来显示算式的可变文本
result.set(' ') # 赋初始值
equation.set('0') # 赋初始值

# 结果显示框
show_uresult = TK.Label(root,bg='white',fg = 'black',font = ('Arail','15'),bd='0',textvariable =equation,anchor='se')
show_dresult = TK.Label(root,bg='white',fg = 'black',font = ('Arail','30'),bd='0',textvariable=result,anchor='se')
show_uresult.place(x='10',y='10',width='300',height='50')
show_dresult.place(x='10',y='60',width='300',height='50')

# 按钮
# 第一行按钮
button_Mc =TK.Button(root,text='Mc',bg='DarkGray',command=clear)
button_Mc.place(x = '10',y='150',width = '60',height='40')
button_Mr =TK.Button(root,text='Mr',bg='DarkGray',command = get_last_result)
button_Mr.place(x = '90',y='150',width = '60',height='40')
button_lbracket=TK.Button(root,text='(',bg='DarkGray',command= lambda : getnum('('))
button_lbracket.place(x = '170',y='150',width = '60',height='40')
button_rbracket=TK.Button(root,text=')',bg='DarkGray',command= lambda : getnum(')'))
button_rbracket.place(x = '250',y='150',width = '60',height='40')
# 第二行按钮
button_7 =TK.Button(root,text='7',bg='DarkGray',command= lambda : getnum('7'))
button_7.place(x = '10',y='205',width = '60',height='40')
button_8 =TK.Button(root,text='8',bg='DarkGray',command= lambda : getnum('8'))
button_8.place(x = '90',y='205',width = '60',height='40')
button_9 =TK.Button(root,text='9',bg='DarkGray',command= lambda : getnum('9'))
button_9.place(x = '170',y='205',width = '60',height='40')
button_division =TK.Button(root,text='÷',bg='DarkGray',command= lambda : getnum('÷'))
button_division.place(x = '250',y='205',width = '60',height='40')
# 第三行按钮
button_4 =TK.Button(root,text='4',bg='DarkGray',command= lambda : getnum('4'))
button_4.place(x = '10',y='260',width = '60',height='40')
button_5 =TK.Button(root,text='5',bg='DarkGray',command= lambda : getnum('5'))
button_5.place(x = '90',y='260',width = '60',height='40')
button_6 =TK.Button(root,text='6',bg='DarkGray',command= lambda : getnum('6'))
button_6.place(x = '170',y='260',width = '60',height='40')
button_multiplication =TK.Button(root,text='X',bg='DarkGray',command= lambda : getnum('x'))
button_multiplication.place(x = '250',y='260',width = '60',height='40')
# 第四行按钮
button_1 =TK.Button(root,text='1',bg='DarkGray',command= lambda :getnum('1'))
button_1.place(x = '10',y='315',width = '60',height='40')
button_2 =TK.Button(root,text='2',bg='DarkGray',command= lambda : getnum('2'))
button_2.place(x = '90',y='315',width = '60',height='40')
button_3 =TK.Button(root,text='3',bg='DarkGray',command= lambda : getnum('3'))
button_3.place(x = '170',y='315',width = '60',height='40')
button_minus =TK.Button(root,text='—',bg='DarkGray',command= lambda : getnum('-'))
button_minus.place(x = '250',y='315',width = '60',height='40')
# 第五行按钮
button_0 =TK.Button(root,text='0',bg='DarkGray',command= lambda : getnum('0'))
button_0.place(x = '10',y='370',width = '60',height='40')
button_point =TK.Button(root,text='.',bg='DarkGray',command= lambda : getnum('.'))
button_point.place(x = '90',y='370',width = '60',height='40')
button_equal=TK.Button(root,text='=',bg='DarkGray',command= run)
button_equal.place(x = '170',y='370',width = '60',height='40')
button_plus =TK.Button(root,text='+',bg='DarkGray',command= lambda : getnum('+'))
button_plus.place(x = '250',y='370',width = '60',height='40')

# 在编写完所有的GUI与相关函数后,我们要让这个窗口不断的循环,做成一直显示的效果,如果没有这一行,主窗口会出现一瞬间然后消失,像是程序没有运行一样
root.mainloop()

8 参考文章

本文在创作过程中参考了下面大佬的文章:

https://blog.csdn.net/a971956955/article/details/81634767


转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达,可以邮件至 xingshuaikun@163.com。

×

喜欢就点赞,疼爱就打赏