实现一个计算器功能需要使用栈。
比如我要计算:7-3*2+1,这个得先乘除后加减,这就需要栈了。
1.自左向右扫描表达式,凡是遇到操作数一律进操作数栈。
2.当遇到运算符时,如果他的优先级比运算符栈栈顶元素的优先级高就栈。反之,取出栈顶运算符和操作数栈顶的两个连续操作数运算,并将结果存入操作数栈,然后继续比较该运算符与栈顶的运算符的优先级。
3.左括号一律进运算符栈,右括号一律不进运算符栈,取出栈顶运算符和操作数栈顶的两个连续操作数运算,并将结果存入操作数栈,直到取出左括号为止。
然而,在Python中由于有eval函数的存在,就不需要使用栈来实现计算器了。
eval(expression, globals=None, locals=None) --- 官方文档中的解释是,将字符串str当成有效的表达式来求值并返回计算结果。
例如:
接下来是利用tkinter编写的代码:
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 |
from tkinter import * from tkinter import messagebox from math import * root = Tk() root.geometry('430x300+400+100') root.title('计算器') # 总显示 frame = Frame() Main = Listbox(frame, height=5, width=50) scb = Scrollbar(frame) scb.pack(side=RIGHT) Main.pack() scb.pack() Main['yscrollcommand'] = scb.set scb['command'] = Main.yview # 记录输入字符串 record = '' # 结果字符串 result = '' # 优先级 priotry = {} priotry['+'] = 0 priotry['-'] = 0 priotry['*'] = 1 priotry['/'] = 1 priotry['%'] = 1 priotry['^'] = 2 # 定义各按钮符号 def appendstr(temp): global record if len(record) != 0: record = record + temp else: record = record + temp if Main.get(0) != '': alltemp = Main.get(0) alltemp = alltemp + temp Main.delete(0) Main.insert(0, alltemp) else: Main.insert(0, temp) # 初始化数字按钮 b = [None] * 10 for i in range(0, 10): b[i] = Button(text=str(i), width=10) # b[i]=Button(text=str(i),width=10,command=lambda:appendstr(str(i)))错误,因为i在后面又被重新使用 b[0]['command'] = lambda: appendstr('0') b[1]['command'] = lambda: appendstr('1') b[2]['command'] = lambda: appendstr('2') b[3]['command'] = lambda: appendstr('3') b[4]['command'] = lambda: appendstr('4') b[5]['command'] = lambda: appendstr('5') b[6]['command'] = lambda: appendstr('6') b[7]['command'] = lambda: appendstr('7') b[8]['command'] = lambda: appendstr('8') b[9]['command'] = lambda: appendstr('9') # 布局数字按钮 for i in range(7, 10): b[i].grid(row=1, column=i - 7) for i in range(4, 7): b[i].grid(row=2, column=i - 4) for i in range(1, 4): b[i].grid(row=3, column=i - 1) b[0].grid(row=4, column=0) def cal(temp): global record global result record = record + '#' alltemp = Main.get(0) Main.delete(0) if temp == '=': result = eval(alltemp) elif temp == '1/x': if result == '0': messagebox.showerror('计算错误', '0没有倒数') else: print(alltemp) result = str(1 / float(alltemp)) elif temp == 'sin': result = str(sin(float(alltemp))) elif temp == 'cos': result = str(cos(float(alltemp))) elif temp == 'tan': result = str(tan(float(alltemp))) alltemp = alltemp + '=' + str(result) Main.insert(0, alltemp) Main.insert(0, '') f = open("我的计算日志.txt", "a+") # 以追加的方式 f.write('\n' + str(alltemp)) # 写完通过\n进行换行 # 清除一个字符 def delete(): global record global Main # 防止多次点击清除上一行 if record == '': return index = record.rfind(' ') record = record[0:index] Main.delete(0) if index - 1 >= 0: # 如果是第一字符就不插入空白行 Main.insert(0, record) # 清楚一行 def deleteall(): global record global Main record = '' Main.delete(0) Main.insert(0, '') # 初始化符号按钮 bdel = Button(text='C', command=delete, width=5) bdelall = Button(text='AC', command=deleteall, width=5) bsub = Button(text='-', width=2, command=lambda: appendstr('-')) badd = Button(text='+', width=2, command=lambda: appendstr('+')) bmul = Button(text='*', width=2, command=lambda: appendstr('*')) bdiv = Button(text='/', width=2, command=lambda: appendstr('/')) bmod = Button(text='%', width=2, command=lambda: appendstr('%')) bcon = Button(text='1/x', width=10, command=lambda: cal('1/x')) bsin = Button(text='sin', width=2, command=lambda: cal('sin')) bcos = Button(text='cos', width=2, command=lambda: cal('cos')) btan = Button(text='tan', width=4, command=lambda: cal('tan')) bpoi = Button(text='.', width=10, command=lambda: appendstr('.')) bequ = Button(text='=', width=2, height=5, command=lambda: cal('=')) # 布局符号按钮 bsub.grid(row=2, column=3) badd.grid(row=1, column=3) bmul.grid(row=3, column=3) bdiv.grid(row=4, column=3) bmod.grid(row=2, column=4) bcon.grid(row=4, column=2) bsin.grid(row=3, column=4) bcos.grid(row=4, column=4) btan.grid(row=1, column=4) bpoi.grid(row=4, column=1) bequ.grid(row=2, column=5, rowspan=3) bdel.grid(row=5, column=0, columnspan=4) bdelall.grid(row=5, column=4, columnspan=4) frame.grid(row=0, column=0, columnspan=10) menubar = Menu(root) root.config(menu=menubar) root.mainloop() |
效果:
当然,计算结果会自动保存到当前目录下的txt文件中去。