eval实现计算器

上次介绍了eval这个函数,也说了可以用来实现计算器,那么这次来实践一下,利用eval来实现一个功能较为完善的计算器,支持加减乘除与指数运算,支持长表达式计算,实现连续计算功能。

明确需求

整体上需要的就是这一个强大的函数,就可以实现一个基本功能的计算器。

while True:  
print(str(eval(input("输入表达式:\n")))

对,基本功能已经实现了,但是这并不是一个功能完备的计算器,我们需要对其做一些功能和安全方向的完善。
上篇文章讲了eval函数的危险,那我们首先需要做的就是语法检查,这里就引出了需要的re模块,回顾re模块的请点击这里.

其次,我们还需要进行异常处理。

对了,我们还需要有连续计算的能力。

到这里,需求基本上也就都明确了,明确了需求,我们就按照这三大块,对我们的程序进行完善,看看最终的两行函数,离我们最终的成品还差多远。

语法检查

导入模块

import re

检查点1–是否含有非法字符

如果输入的表达式含有字母和非运算符,那么这个表达式就是不合法的,对这样的表达式我们拒绝它执行,并且给与他友好性的提示,提示输入正确的表达式,并返回-1并表示表达式非法。

def CharErrorCheck(str_in):
if re.findall(r'[&a-zA-Z<>,?~!@#$%";:]', str_in): # 正则表达式校验输入字符串的合法性
print('错误:表达式包含非法字符,请重新输入\n')
return 1
else:
return -1

检查点2–括号是否平衡

确保括号成对出现,如不符合,给与友好型提示。返回-1表示表达式不合法。

def BracketUnbalanceCheck(str_in):
num = 0
for i in str_in:
if i == '(':
num += 1
elif i == ')':
num -= 1
if num != 0: # 括号不平衡
print("错误:输入的括号不平衡,请重新输入\n")
return 1
else: # 括号平衡
return -1

进行语法检查后,就要开始计算了,那么这里首先就要加上继续计算的功能,就是上一次计算结束后的结果进行保留,可以继续使用上一次的结果作为输入。

继续计算功能

其实。要添加这个功能不难,仅仅需要一个标志位来判断是不是继续上一次的计算。这时候就可能有人要问了,怎么判断是不是想要继续计算呢?

很简单,如果继续计算的话,那么他新输入的第一个字符就是运算符,如果不是运算符,那么就是开启了一个新的运算式。

判断是否为继续计算

如果判定为继续计算,那么返回'continue',否则返回 'new'

def InputExpression():
global exprs
while not (CharErrorCheck(exprs) == -1 and BracketUnbalanceCheck(exprs) == -1): # 直到得到一个合法的表达式
exprs = input("继续输入表达式:\n")
m = re.match(r'^[\^/\*+\-\\]\w*', exprs) # 匹配输入字符串的第一个字符是否是运算符,判断继续运算还是开始新计算
if m:
return 'continue'
else:
return 'new'

开始计算与异常处理

根据全局变量flag,适当修改计算式。
如果含有几次方的计算,将^修改为**
使用eval函数进行计算
接着使用try语句块进行处理,语法错误或是0当作除数,给与友好型提示。

def Compute(flag):
global exprs
global sum
exprs = exprs.replace('^', '**') # 将^替换为**
if flag == 'continue':
exprs = str(sum) + exprs
try:
sum = eval(exprs)
print(exprs)
print("=" + str(sum))
except SyntaxError:
print("错误:继续计算时出现语法错误,程序返回\n")
except ZeroDivisionError:
print("错误:除数不能为0,程序返回\n")

锦上添花

至此所有的需求都已经实现,在主函数里面串起来即可。当然还可以添加一些锦上添花的功能,比如添加版权信息或是使用pyinstaller进行函数打包成exe都是可以的。具体怎么优化就看你了。

附录-源码

完整源码请点击这里获取

-------------本文结束感谢您的阅读-------------