对用python实现的非函数计算器的改进

前边博文用python实现了一个非函数计算器,后发现了一个严重错误,在前边博文中做了修改,后又发现了一些错误和不合理的操作。本文将对所有这些做详细说明,并给出解决方法,最后给出修改后的全部代码,使读者可以和前边博文中的代码进行比较。
第1个错误在第5行,该函数用运算符+、-、×、÷分割字符串s为多个子字符串存到列表中,取出末项(即正在输入的整数或浮点数)保存到s1中。函数split的第1个参数字符串是正则表达式,原是:r’+|-|×|÷]’,该正则表达式将不认为÷为分割符,这样在包括除法的运算中,程序可能出错,这是一个严重的错误。正确的正则表达式为:r’+|-|×|÷|]’。该错误前边博文中已做修改。
第2个错误是未检查除法算数表达式中的除数是否是0。被0除在运行环境中会报错,但计算器程序不会崩溃,第42行代码:label[‘text’]=str(eval(s)),如eval(s)出错,将会返回原字符串s,换句话讲,label显示的仍是原字符串,计算器可继续工作,修改被0除错误,仍可得到正确结果。但好的程序代码应检查该错误。检查的基本方法就是判断÷后的整数或浮点数是否为0。在输入÷后,开始输入除数,逐次单击按钮输入数字或小数点,当输入+ -×÷=中任一个后,表示除数完成输入,应开始检查除数是否为0。此时变量s是已输入的算数表达式的所有数据(见第4条语句),请注意并不包括最后输入的这个运算符,它正在被检查是否能被添加到算数表达式中,因此变量s1是输入的除数(见第5条语句)。下边判断语句如成立表示除数为0,如最后输入的是=,不应进行计算,如最后输入的是运算符,也不能不能加到Label的text属性中,即应退出事件函数。可增加一个Label控件提示用户除数不能为0,在计算器程序被运行和事件函数开始将这个Label的text清空,保证在下一次输入正确时,提示消失,如除数仍为0,重新提示。本文未实现该功能。

if float(s1)==0 and s[-(len(s1)+1)]=='÷':    #见第19条和第36条语句

但有两种情况下不能做此检查。第1种,在计算器程序被运行后或单击了标题为C的清空按钮后,算数表达式为空。先输入数字,然后输入运算符或=,此时因还未输入除数,不能做此检查。在此情况下,s==s1。第2种,连续输入两个运算符,此时s1为空,float(s1)出错,在此情况下,len(s1)==0。因此如满足下边语句,才可做除数是否为0检查。

if s!=s1 and len(s1)!=0:       #见第18条和第35条语句

第3个错误是,整个算数表达式的第一项是+ - × ÷中任一个,函数eval(s)计算出错。
第4个错误是,在计算器程序被运行后或单击了清空(C )按钮后,算数表达式为空,此时输入按钮=,对这个为空的算数表达式进行计算,函数eval(s)计算出错。
这两个错误的解决方法是计算器程序被运行后或单击了清空(C )按钮后,令label控件属性text的值为0,这样整个算数表达式首位就不会是运算符了,也不可能是空了。见第47条和第33条语句。
最后一个是使操作更合理。见第21条和第22条语句,原来第22条语句是return,其功能是如果连续输入两个运算符,第2个输入的运算符被忽略。现在第22条语句改为如下语句,将第1个输入的运算符替换为第2个输入的运算符。

label['text']=s[0:-1]+x     #删除字符串最后一个运算符,再增加第2个输入的运算符

修改后的全部代码如下。水平有限,可能还有错,欢迎指正。

import tkinter
import re
def btnClick(x):           #所有按钮的事件函数,有1个参数是被点击按钮标题
    s=label['text']    
    s1= re.split(r'\+|-|×|÷|]',s)[-1]  #用运算符分割label标题存到列表,取出末项
    if x in '0123456789':
        if '.' not in s1 and  s1.startswith('0'):  #去掉整数前的0
            s=s[0:-1]
        label['text']=s+x
    elif x == '.':
        if '.' in s1:   #浮点数只能有1个小数点
            return
        if s1=='':      #第一次输入小数点,在其前边增加0
            label['text']+='0.'
        else:
            label['text']+='.'
    elif x in ['+','-','×','÷']:
        if s!=s1 and len(s1)!=0:  #s!=s1保证不是仅有一个运算符,后1条件保证能转换为浮点数
            if float(s1)==0 and s[-(len(s1)+1)]=='÷':   #如0前边是÷号,表示被0除
                return#可增加Label控件提示不能被0除,在def btnClick(x):第一条语句清空
        if s[-1] in ['+','-','×','÷']:      #两个运算符不能相邻
            label['text']=s[0:-1]+x         #用新输入的运算符替换上次输入的运算符
        elif s[-1]=='.':  #其前边是小数点,增加0
            label['text']+=('0'+x)
        else:
            label['text']+=x
    elif x=='←':
        s=s[0:-1]   #删掉最后1项
        if len(s)==0:
            s='0'
        label['text']=s
    elif x=='c':
        label['text']='0'
    else:   #最后是单击=键
        if s!=s1 and len(s1)!=0:
            if float(s1)==0 and s[-(len(s1)+1)]=='÷':
                return
        if s[-1] in ['+','-','×','÷']:      #最后一个字符是运算符,eval计算出错
            s=s[0:-1]                       #删掉这个运算符
        s=s.replace('×','*',s.count('×'))   #eval不认识运算符×和÷,替换为*和/ 
        s=s.replace('÷','/',s.count('÷'))
        label['text']=str(eval(s))      
root = tkinter.Tk()        #初始化窗口
root.title('计算器')        #窗口标题
root.geometry("320x370")   #窗口宽300,高=500
root.resizable(width=False,height=False) #设置窗口是否可变,宽不可变,高不可变,默认为True
label=tkinter.Label(root,text='0',fg='red',font=("Arial",20),anchor="e")
label.place(x=20,y=10,width=280,height=40)
numbers=list('.0=321+654-987×÷←c')   #列表,所有按钮标题可显示的数字1到8和空白  %
for row in range(5): #row=行,0,1,2
    for col in range(4): #col=列,0,1,2        
        if row==4 and col==2:
            break
        s=numbers.pop()
        button=tkinter.Button(root,command=lambda x=s:btnClick(x),fg='red',font=("Arial",20))
        button['text']=s    #将列表numbers最后一项作为按钮标题并将列表最后1项删除
        button.place(x=45+col*60,y=60+row*60,width=50,height=50)
root.mainloop()
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值