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 相关文章推荐
Python3处理文件中每个词的方法
May 22 Python
浅析Python中的for 循环
Jun 09 Python
python3音乐播放器简单实现代码
Apr 20 Python
动感网页相册 python编写简单文件夹内图片浏览工具
Aug 17 Python
Python 操作MySQL详解及实例
Apr 30 Python
利用Python读取文件的四种不同方法比对
May 18 Python
Python常用数据类型之间的转换总结
Sep 06 Python
双向RNN:bidirectional_dynamic_rnn()函数的使用详解
Jan 20 Python
Python3爬虫中Ajax的用法
Jul 10 Python
Python self用法详解
Nov 28 Python
Python快速优雅的批量修改Word文档样式
May 20 Python
请求模块urllib之PYTHON爬虫的基本使用
Apr 08 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
CodeIgniter使用phpcms模板引擎
2013/11/12 PHP
Yii2中事务的使用实例代码详解
2016/09/07 PHP
PHP简单留言本功能实现代码
2017/06/09 PHP
php设计模式之迭代器模式实例分析【星际争霸游戏案例】
2020/04/07 PHP
Nigma vs AM BO3 第一场2.13
2021/03/10 DOTA
Add a Table to a Word Document
2007/06/15 Javascript
JavaScript 嵌套函数指向this对象错误的解决方法
2010/03/15 Javascript
理解Javascript_01_理解内存分配原理分析
2010/10/11 Javascript
Javascript事件热键兼容ie|firefox
2010/12/30 Javascript
jquery清空textarea等输入框实现代码
2013/04/22 Javascript
jquery动态增加删除表格行的小例子
2013/11/14 Javascript
微信小程序 时间格式化(util.formatTime(new Date))详解
2016/11/16 Javascript
基于jquery实现五星好评
2017/11/18 jQuery
详解PHP后期静态绑定分析与应用
2018/03/21 Javascript
简单的vuex 的使用案例笔记
2018/04/13 Javascript
vue 组件使用中的一些细节点
2018/04/25 Javascript
浅谈如何使用webpack构建多页面应用
2018/05/30 Javascript
vue 组件简介
2020/07/31 Javascript
vue从后台渲染文章列表以及根据id跳转文章详情详解
2020/12/14 Vue.js
[13:38]2015国际邀请赛中国战队出征仪式
2015/05/29 DOTA
Python中的推导式使用详解
2015/06/03 Python
Python实现文件按照日期命名的方法
2015/07/09 Python
python实现猜数字小游戏
2020/03/24 Python
使用matplotlib动态刷新指定曲线实例
2020/04/23 Python
简单了解Java Netty Reactor三种线程模型
2020/04/26 Python
突袭HTML5之Javascript API扩展2—地理信息服务及地理位置API学习
2013/01/31 HTML / CSS
Tory Burch美国官方网站:美国时尚生活品牌
2016/08/01 全球购物
Marmot土拨鼠官网:美国专业户外运动品牌
2018/01/11 全球购物
意大利奢侈品综合电商网站:MODES
2019/12/14 全球购物
澳大利亚家具商店:Freedom
2020/12/17 全球购物
database面试题
2013/03/28 面试题
小班下学期评语
2014/05/04 职场文书
员工评语范文
2014/12/31 职场文书
小学数学教师研修感悟
2015/11/18 职场文书
2016年世界人口日宣传活动总结
2016/04/05 职场文书
使用nginx动态转换图片大小生成缩略图
2021/03/31 Servers