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实现的二维码生成小软件
Jul 11 Python
Python实现抓取页面上链接的简单爬虫分享
Jan 21 Python
Python爬虫代理IP池实现方法
Jan 05 Python
Python基于多线程实现抓取数据存入数据库的方法
Jun 22 Python
对python制作自己的数据集实例讲解
Dec 12 Python
Django框架视图函数设计示例
Jul 29 Python
python使用if语句实现一个猜拳游戏详解
Aug 27 Python
python 实现dict转json并保存文件
Dec 05 Python
python访问hdfs的操作
Jun 06 Python
Python 私有属性和私有方法应用场景分析
Jun 19 Python
python中Mako库实例用法
Dec 31 Python
python​格式化字符串
Apr 20 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+mysql写的简单留言本实例代码
2008/07/25 PHP
php安全开发 添加随机字符串验证,防止伪造跨站请求
2013/02/14 PHP
ThinkPHP3.2框架使用addAll()批量插入数据的方法
2017/03/16 PHP
告诉大家什么是JSON
2008/06/10 Javascript
js实现多选项切换导航菜单的方法
2015/02/06 Javascript
浅谈js图片前端预览之filereader和window.URL.createObjectURL
2016/06/30 Javascript
jQuery 选择器(61种)整理总结
2016/09/26 Javascript
JavaScript实现替换字符串中最后一个字符的方法
2017/03/07 Javascript
深入理解vue-router之keep-alive
2017/08/31 Javascript
使用InstantClick.js让页面提前加载200ms
2017/09/12 Javascript
mpvue 如何使用腾讯视频插件的方法
2018/07/16 Javascript
vue+element-ui动态生成多级表头的方法
2018/08/28 Javascript
angularjs1.5 组件内用函数向外传值的实例
2018/09/30 Javascript
Vue一个案例引发的递归组件的使用详解
2018/11/15 Javascript
浅谈Vue CLI 3结合Lerna进行UI框架设计
2019/04/14 Javascript
vue 2.5.1 源码学习 之Vue.extend 和 data的合并策略
2019/06/04 Javascript
Vue.js实现大屏数字滚动翻转效果
2019/11/29 Javascript
js实现上传图片并显示图片名称
2019/12/18 Javascript
深入解读VUE中的异步渲染的实现
2020/06/19 Javascript
nuxt 服务器渲染动态设置 title和seo关键字的操作
2020/11/05 Javascript
Python中输出ASCII大文字、艺术字、字符字小技巧
2015/04/28 Python
Python MySQLdb Linux下安装笔记
2015/05/09 Python
详解python中的json的基本使用方法
2016/12/21 Python
python实现识别手写数字 python图像识别算法
2020/03/23 Python
PyQt5 QTableView设置某一列不可编辑的方法
2019/06/25 Python
Django权限设置及验证方式
2020/05/13 Python
Python使用windows设置定时执行脚本
2020/11/12 Python
压铸汽车模型收藏家:Diecastmodelswholesale.com
2016/12/21 全球购物
全球知名的珠宝首饰品牌:Kay Jewelers
2018/02/11 全球购物
马来西亚综合购物网站:Lazada马来西亚
2018/06/05 全球购物
Blancsom美国/加拿大:服装和生活用品供应商
2018/07/27 全球购物
德国帽子专家:Hutshopping
2019/11/03 全球购物
Lucene推荐的分页方式是什么?
2015/12/07 面试题
金融管理专业求职信
2014/07/10 职场文书
《绝招》教学反思
2016/02/20 职场文书
maven依赖的version声明控制方式
2022/01/18 Java/Android