Python实现简单的四则运算计算器


Posted in Python onNovember 02, 2016

一、算法

     1、算法的主要思想就是将一个中缀表达式(Infix expression)转换成便于处理的后缀表达式(Postfix expression),然后借助于栈这个简单的数据结构,计算出表达式的结果。

     2、关于如何讲普通的表达式转换成后缀表达式,以及如何处理后缀表达式并计算出结果的具体算法描述不在此叙述了,书上有详细的说明。

二、简易计算器

使用说明

使用该计算器类的简单示例如下:

# usage
c = Calculator()
print('result: {:f}'.formart(c.get_result('1.11+2.22-3.33*4.44/5.55')))
# output:
result: 0.666000

测试案例

为了对这个计算器进行有效地检验,设计了几组测试案例,测试结果如下:

Test No.1: (1.11) = 1.110000
Test No.2: 1.11+2.22-3.33*4.44/5.55 = 0.666000
Test No.3: 1.11+(2.22-3.33)*4.44/5.55 = 0.222000
Test No.4: 1.11+(2.22-3.33)*(4.44+5.55)/6.66 = -0.555000
Test No.5: 1.11*((2.22-3.33)*(4.44+5.55))/(6.66+7.77) = -0.852992
Test No.6: (1.11+2.22)*(3.33+4.44)/5.55*6.66 = 31.048920
Test No.7: (1.11-2.22)/(3.33+4.44)/5.55*(6.66+7.77)/(8.88) = -0.041828
Test No.8: Error: (1.11+2.22)*(3.33+4.44: missing ")", please check your expression
Test No.9: Error: (1.11+2.22)*3.33/0+(34-45): divisor cannot be zero
Test No.10: Error: 12+89^7: invalid character: ^

实现代码

栈的实现

栈实际上就是一个被限制操作的表,所有的操作只能在栈的顶端(入栈、出栈等),以下是使用Python代码实现的简单的栈:

class Stack(object):
  """
  The structure of a Stack.
  The user don't have to know the definition.
  """
  def __init__(self):
    self.__container = list()
  def __is_empty(self):
    """
    Test if the stack is empty or not
    :return: True or False
    """
    return len(self.__container) == 0
  def push(self, element):
    """
    Add a new element to the stack
    :param element: the element you want to add
    :return: None
    """
    self.__container.append(element)
  def top(self):
    """
    Get the top element of the stack
    :return: top element
    """
    if self.__is_empty():
      return None
    return self.__container[-1]
  def pop(self):
    """
    Remove the top element of the stack
    :return: None or the top element of the stack
    """
    return None if self.__is_empty() else self.__container.pop()
  def clear(self):
    """
    We'll make an empty stack
    :return: self
    """
    self.__container.clear()
    return self

计算器类的实现

在计算器类中,我们将表达式的合法性验证单独放在一个函数中完成,但是实际上如果需要,也可以直接放在中缀表达式转后缀表达式的函数中实现,这样只需要一次遍历表达式即可同时完成验证和转换工作。但是为了保持结构清晰,还是分开来实现比较好,每个函数尽可能最好一件事情才是比较实在的。

在该计算器类中,有很多种极端的情况没有被考虑进去,因为那样的话整个实现的代码会更多。不过,可以在后期为整个类继续扩展,添加新的功能也是可以的。目前实现的就是主要框架,包括基本的错误检测和运算,重点时学习运用栈这个看似简单却强大的数据结构解决问题。

class Calculator(object):
  """
  A simple calculator, just for fun
  """
  def __init__(self):
    self.__exp = ''
  def __validate(self):
    """
    We have to make sure the expression is legal.
    1. We only accept the `()` to specify the priority of a sub-expression. Notes: `[ {` and `] }` will be
    replaced by `(` and `)` respectively.
    2. Valid characters should be `+`, `-`, `*`, `/`, `(`, `)` and numbers(int, float)
    - Invalid expression examples, but we can only handle the 4th case. The implementation will
    be much more sophisticated if we want to handle all the possible cases.:
      1. `a+b-+c`
      2. `a+b+-`
      3. `a+(b+c`
      4. `a+(+b-)`
      5. etc
    :return: True or False
    """
    if not isinstance(self.__exp, str):
      print('Error: {}: expression should be a string'.format(self.__exp))
      return False
    # Save the non-space expression
    val_exp = ''
    s = Stack()
    for x in self.__exp:
      # We should ignore the space characters
      if x == ' ':
        continue
      if self.__is_bracket(x) or self.__is_digit(x) or self.__is_operators(x) \
          or x == '.':
        if x == '(':
          s.push(x)
        elif x == ')':
          s.pop()
        val_exp += x
      else:
        print('Error: {}: invalid character: {}'.format(self.__exp, x))
        return False
    if s.top():
      print('Error: {}: missing ")", please check your expression'.format(self.__exp))
      return False
    self.__exp = val_exp
    return True
  def __convert2postfix_exp(self):
    """
    Convert the infix expression to a postfix expression
    :return: the converted expression
    """
    # highest priority: ()
    # middle: * /
    # lowest: + -
    converted_exp = ''
    stk = Stack()
    for x in self.__exp:
      if self.__is_digit(x) or x == '.':
        converted_exp += x
      elif self.__is_operators(x):
        converted_exp += ' '
        tp = stk.top()
        if tp:
          if tp == '(':
            stk.push(x)
            continue
          x_pri = self.__get_priority(x)
          tp_pri = self.__get_priority(tp)
          if x_pri > tp_pri:
            stk.push(x)
          elif x_pri == tp_pri:
            converted_exp += stk.pop() + ' '
            stk.push(x)
          else:
            while stk.top():
              if self.__get_priority(stk.top()) != x_pri:
                converted_exp += stk.pop() + ' '
              else:
                break
            stk.push(x)
        else:
          stk.push(x)
      elif self.__is_bracket(x):
        converted_exp += ' '
        if x == '(':
          stk.push(x)
        else:
          while stk.top() and stk.top() != '(':
            converted_exp += stk.pop() + ' '
          stk.pop()
    # pop all the operators
    while stk.top():
      converted_exp += ' ' + stk.pop() + ' '
    return converted_exp
  def __get_result(self, operand_2, operand_1, operator):
    if operator == '+':
      return operand_1 + operand_2
    elif operator == '-':
      return operand_1 - operand_2
    elif operator == '*':
      return operand_1 * operand_2
    elif operator == '/':
      if operand_2 != 0:
        return operand_1 / operand_2
      else:
        print('Error: {}: divisor cannot be zero'.format(self.__exp))
        return None
  def __calc_postfix_exp(self, exp):
    """
    Get the result from a converted postfix expression
    e.g. 6 5 2 3 + 8 * + 3 + *
    :return: result
    """
    assert isinstance(exp, str)
    stk = Stack()
    exp_split = exp.strip().split()
    for x in exp_split:
      if self.__is_operators(x):
        # pop two top numbers in the stack
        r = self.__get_result(stk.pop(), stk.pop(), x)
        if r is None:
          return None
        else:
          stk.push(r)
      else:
        # push the converted number to the stack
        stk.push(float(x))
    return stk.pop()
  def __calc(self):
    """
    Try to get the result of the expression
    :return: None or result
    """
    # Validate
    if self.__validate():
      # Convert, then run the algorithm to get the result
      return self.__calc_postfix_exp(self.__convert2postfix_exp())
    else:
      return None
  def get_result(self, expression):
    """
    Get the result of an expression
    Suppose we have got a valid expression
    :return: None or result
    """
    self.__exp = expression.strip()
    return self.__calc()
  """
  Utilities
  """
  @staticmethod
  def __is_operators(x):
    return x in ['+', '-', '*', '/']
  @staticmethod
  def __is_bracket(x):
    return x in ['(', ')']
  @staticmethod
  def __is_digit(x):
    return x.isdigit()
  @staticmethod
  def __get_priority(op):
    if op in ['+', '-']:
      return 0
    elif op in ['*', '/']:
      return 1

总结

以上就是利用Python实现简单四则运算计算器的全部内容,希望本文的内容对大家的学习或者工作能有所帮助,如果有疑问大家可以留言交流。

参考

《数据结构与算法(C语言)》上相关章节算法描述

Python 相关文章推荐
Python数据结构与算法之图的最短路径(Dijkstra算法)完整实例
Dec 12 Python
tensorflow入门之训练简单的神经网络方法
Feb 26 Python
python将每个单词按空格分开并保存到文件中
Mar 19 Python
Python基于Floyd算法求解最短路径距离问题实例详解
May 16 Python
Python学习小技巧总结
Jun 10 Python
Python读取txt文件数据的方法(用于接口自动化参数化数据)
Jun 27 Python
对django中render()与render_to_response()的区别详解
Oct 16 Python
Python OpenCV读取png图像转成jpg图像存储的方法
Oct 28 Python
Python如何优雅获取本机IP方法
Nov 10 Python
Python imageio读取视频并进行编解码详解
Dec 10 Python
python cv2读取rtsp实时码流按时生成连续视频文件方式
Dec 25 Python
Python实现SMTP邮件发送
Jun 16 Python
利用Python命令行传递实例化对象的方法
Nov 02 #Python
Python 性能优化技巧总结
Nov 01 #Python
python字典多键值及重复键值的使用方法(详解)
Oct 31 #Python
浅谈django中的认证与登录
Oct 31 #Python
python 把数据 json格式输出的实例代码
Oct 31 #Python
python中json格式数据输出的简单实现方法
Oct 31 #Python
python并发编程之多进程、多线程、异步和协程详解
Oct 28 #Python
You might like
php将服务端的文件读出来显示在web页面实例
2016/10/31 PHP
Laravel 之url参数,获取路由参数的例子
2019/10/21 PHP
html中table数据排序的js代码
2011/08/09 Javascript
推荐5 个常用的JavaScript调试技巧
2015/01/08 Javascript
jquery+php随机生成红包金额数量代码分享
2015/08/27 Javascript
基于jquery实现下拉框美化特效
2016/02/02 Javascript
jquery树形菜单效果的简单实例
2016/06/06 Javascript
全面了解javascript中的错误处理机制
2016/07/18 Javascript
AngularJS模块详解及示例代码
2016/08/17 Javascript
利用bootstrapValidator验证UEditor
2016/09/14 Javascript
jQuery插件HighCharts实现的2D对数饼图效果示例【附demo源码下载】
2017/03/09 Javascript
bootstrap IE8 兼容性处理
2017/03/22 Javascript
js中的DOM模拟购物车功能
2017/03/22 Javascript
bootstrap基本配置_动力节点Java学院整理
2017/07/14 Javascript
微信小程序之电影影评小程序制作代码
2017/08/03 Javascript
JS将网址url转化为JSON格式的方法
2018/07/02 Javascript
vue+elementUI实现表单和图片上传及验证功能示例
2019/05/14 Javascript
vue实现百度语音合成的实例讲解
2019/10/14 Javascript
[03:44]2014DOTA2国际邀请赛 71专访:DK战队赛前讨论视频遭泄露
2014/07/13 DOTA
Sanic框架安装与简单入门示例
2018/07/16 Python
python实现对输入的密文加密
2019/03/20 Python
Python的log日志功能及设置方法
2019/07/11 Python
python实现倒计时小工具
2019/07/29 Python
PyQt5高级界面控件之QTableWidget的具体使用方法
2020/02/23 Python
python selenium自动化测试框架搭建的方法步骤
2020/06/14 Python
html5手机键盘弹出收起的处理
2020/01/20 HTML / CSS
html5视频自动横过来自适应页面且点击播放功能的实现
2020/06/03 HTML / CSS
澳大利亚男士西服品牌:M.J.Bale
2018/02/06 全球购物
艺术专业大学生自我评价
2013/09/22 职场文书
运动会领导邀请函
2014/01/10 职场文书
消防安全承诺书
2014/05/22 职场文书
作风建设演讲稿
2014/05/23 职场文书
大学生村官考核材料
2014/05/23 职场文书
药店促销活动总结
2014/07/10 职场文书
党支部三会一课计划
2014/09/24 职场文书
关于html选择框创建占位符的问题
2021/06/09 HTML / CSS