栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Python

使用 Python 语言实现一个计算器(大一期末项目附源码)

Python 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

使用 Python 语言实现一个计算器(大一期末项目附源码)

提示:本计算器是一个不带界面的,只需要将要计算的计算式传入就可以使用

文章目录
  • 前言
  • 一、计算器功能
  • 二、计算器设计思想
    • 1.复杂运算简单化
    • 2.不带括号的计算式处理
    • 3.不带括号的计算式的计算
      • 3.1 Python内置函数eval()
      • 3.2 特殊计算处理
      • 3.3 调用eval()将特殊计算处理完成后的计算式进行最后计算
    • 4.最后的计算
  • 源码
    • 计算式字符串处理层(文件名:CalculatorDataConller.py)
    • 计算层(文件名:CalculatorCalculate.py)
    • 特殊计算处理层(文件名:CalculatorSpecialCalculating.py)
    • 调用层(文件名:CalculatorInterface.py)
  • 源码文件


前言

对数 输入规则:底数log真数
开方 输入规则:√被开发数
阶乘 输入规则:正整数!
三角函数 接收数据的单位为:角度


提示:以下是本篇文章正文内容,下面案例可供参考

一、计算器功能

计算器可以实现:
            加(+)、减(-)、乘(*)、除(/)、整除(//)、求余(%)
            对数(log)、乘方(**)、开根(√)、阶乘(!)、正弦(sin)
            余弦(cos)、正切(tan)、及它们的符合正确语法的复合运算


二、计算器设计思想 1.复杂运算简单化

一个计算式中可能会出现多个括号,括号中是一个小的运算式;计算器先将整个计算式按括号拆分成一个列表,并计算括号中的小计算式,用结果替换括号部分在列表中的位置;重复这个步骤,整个计算式被拆分为没有括号列表

# 如:
'(2log4+10**2+20)-100+50/10*(100+2+6)'
# 去括号后:
['122', '-100+50/10*', '108']
2.不带括号的计算式处理

将不带括号的计算式(可以是括号内部的小计算式),从基本符号([‘+’, ‘-’, ‘*’, ‘/’, ‘%’])处拆分为几个部分,并用一个列表进行存储。
注意:上述符号在拆分过程中,会将符号与跟符号相关的数字分离;其他运算符看作特殊的运算符,如:log、!、cos等,在拆分过程中不会将符号与作用的数字相分离,而是当作一个整体

# 如:
'122-100+50/10*108+2log4+cos90+6!+2**2*2'
# 拆分后:
['122', '-', '100', '+', '50', '/', '10', '*', '108', '+', '2log4', '+', 'cos90', '+', '6!', '+', '2**2', '*', '2']
3.不带括号的计算式的计算 3.1 Python内置函数eval()

python内置的eval()函数可以将表达正确的简单计算的计算式字符串计算出结果,所以不用另外编写 “加(+)、减(-)、乘(*)、除(/)、整除(//)、求余(%)、乘方(**)” 这些计算的函数,直接将只含有这些计算的计算式输入eval()中就可以返回计算结果

如:122-100+50/10*108+2**2*2 就可以直接传入eval()进行计算

3.2 特殊计算处理

在 2 中,得到计算式拆分为列表后,遍历列表中的每个子字符串,如果发现其中有特殊运算,如:log,三角函数,阶乘、开根,就调用相关函数将其计算出来,并将结果替换在列表中相应的位置

# 如:
['122', '-', '100', '+', '50', '/', '10', '*', '108', '+', '2log4', '+', 'cos90', '+', '6!', '+', '2**2', '*', '2']
# 特殊计算处理后:
['122', '-', '100', '+', '50', '/', '10', '*', '108', '+', '2', '+', '0', '+', '720', '+', '2**2', '*', '2']
3.3 调用eval()将特殊计算处理完成后的计算式进行最后计算

将特殊计算处理完成后的计算式列表连接成一个字符串,并传入eval()中,就可以得到结果:

# 特殊计算处理后的计算式列表
['122', '-', '100', '+', '50', '/', '10', '*', '108', '+', '2', '+', '0', '+', '720', '+', '2**2', '*', '2']
# 连接成字符串后
'122-100+50/10*108+2+0+720+2**2*2'
# 调用eval
print(eval('122-100+50/10*108+2+0+720+2**2*2'))
# 结果
1292.0

4.最后的计算

将 1 中计算式拆分后的列表,连接为一个字符串,并将字符串送入 3 中,经过 3.2 和 3.3 处理,便可以得到最后的结果

# 1中所得列表
['122', '-100+50/10*', '108']
# 连接
'122-100+50/10*108'
# 经过3.2和3.3处理和计算结果
562.0

源码 计算式字符串处理层(文件名:CalculatorDataConller.py)
import CalculatorCalculate as cal


# 用来处理界面传入的需要计算的表达式
class Controller:
    # 先处理括号,式子中有括号,先计算括号中式子的值,再将计算结果替换式子中的括号部分
    def processingData1(self, shizi):
        # 用于存储去除括号后的拆分的式子列表。如果碰到括号就将式子分割,将括号前面部分放入列表,再计算括号中式子的值,最后将结果放在括号前面部分的后面
        shizi_list = []
        # 每次去除括号后,就重新进行一次括号检测,检测的式子为这次去除的括号的后面的式子
        daiqie = str(shizi)

        # 采用用一个死循环,检测括号,直到所有括号替换为数值,就可以结束死循环
        while True:
            # 遍历需要检测括号的式子中的每个字符
            for i in range(len(daiqie)):
                c = daiqie[i]
                # 用于存储左括号前面的一部分式子
                front_str = ""
                # 用于存储左括号后面的一部分式子,用来查找右括号
                back_str = ""

                # 判断这个字符是不是左括号,
                if c == '(':
                    # 如果左括号且不是在界面传入的计算式的第一位,就需要将左括号前面部分放入 shizi_list 列表
                    if i != 0:
                        front_str = daiqie[:i]
                        # 将左括号之前的一部分式子放入列表
                        shizi_list.append(front_str)
                    # 左括号后面的式子
                    back_str = daiqie[i + 1:]

                    # 遍历左括号后面的式子的每一个字符,寻找右括号
                    for k in range(len(back_str)):
                        j = back_str[k]

                        # 找到右括号,如果右括号不是式子的最后一个字符,就将括号中的式子计算出来,结果放入 shizi_list 列表
                        # 并且把右括号后面的式子放入 daiqie 变量,用于下一轮括号检测
                        if j == ')' and k != len(back_str) - 1:
                            # 括号中的式子
                            target = back_str[:k]
                            # 计算括号中的式子,并将结果放入 shizi_list 列表
                            shizi_list.append(self.processingData2(target))
                            # 右括号后面的式子
                            daiqie = back_str[k + 1:]
                            # 结束检测左括号后面式子中右括号的 for 循环
                            break
                        # 找到右括号,如果右括号是式子的最后一个字符,就将括号中的式子计算出来,结果放入 shizi_list 列表
                        # 并且把 daiqie 变量设为空字符串,用来标志括号已经全部处理完成,可以结束 while 死循环
                        elif j == ')' and k == len(back_str) - 1:
                            # 括号中的式子
                            target = back_str[:k]
                            # 计算括号中的式子,并将结果放入 shizi_list 列表
                            shizi_list.append(self.processingData2(target))
                            # 设置括号全部处理完成标志
                            daiqie = ""
                            # 结束检测左括号后面式子中右括号的 for 循环
                            break
                    # 右括号查找完成,表示一个括号处理完成,可以重新开始括号检测,检测后部分式子中的括号
                    break

            # 如果待检测括号式子为空,表明括号处理完成,可以结束 while 死循环
            if daiqie == "":
                break
            # 如果待检测括号式子中没有括号,也表明括号处理完成,就将式子添加到 shizi_list 表中,结束 while 死循环
            elif '(' not in daiqie and ')' not in daiqie:
                shizi_list.append(daiqie)
                break

        # 将处理好括号的计算式拆分的列表拼接成计算式
        jisuanshi = ""
        for i in shizi_list:
            jisuanshi += str(i)

        # 将没有没括号的式子,传入无括号式子处理的方法中,进行处理得到结果并返回
        result = float(self.processingData2(jisuanshi))
        return result

    # 没有括号的计算式处理,将式子按基本符号(['+', '-', '*', '/', '%'])拆分开得到一个式子的拆分列表,并调用内部计算功能得到结果
    # 其他运算符,如:**,//,log,√,cos,sin,tan,!,看作是特殊的运算符,这类符号需要将符号和符号作用的数字看作一个整体
    def processingData2(self, basic_jisuanshi):
        # 拆分计算式的标志
        character = ['+', '-', '*', '/', '%']
        num_list = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']
        # 存储式子拆分后的小字符串的列表
        character_list = []
        # 存储拆分标志后面的式子,在拆分过程中,这个字符串的长度必定会比传入的计算式长度越来越小,存在一定差值
        # 差值为 character_list 中每个字符串长度之和
        daiqie = basic_jisuanshi

        # b是用来区别“*”与“**”,“/”与“//”,防止将“**”和“//”拆分
        b = True
        # 遍历无括号计算式中的每一个字符
        for j in range(len(basic_jisuanshi)):
            i = basic_jisuanshi[j]

            # 如果这个字符是“*”或“/”,则需要判断是否是“**”或“//”;如果是特殊运算符,就不进行拆分,将b设置为False,直到碰到数字字符才将b设置为True
            # 相当于加锁,碰到“**”和“//”就上锁,不进行拆分;直到循环走过这两个符号,就会遍历到数字字符,表明可以放开这把锁
            if (i == '*' and basic_jisuanshi[j + 1] == '*') or (i == '/' and basic_jisuanshi[j + 1] == '/'):
                b = False
            elif i in num_list:
                b = True

            # 如果字符是拆分标志,并且没有被加锁,就可以进行拆分
            if i in character:
                if b:
                    # 如果需要进行拆分,那么拆分标识符号前面的必然是一个整体,用切片的方法进行分割,可以避免split带来的误切问题
                    # 拆分时,索引j为原计算式中的索引,与 daiqie 中需要切分的字符位置存在一定差值,故j需要减去这个差值,才能对应上在 daiqie
                    # 中需要切分的字符的位置
                    character_list.append(daiqie[:j - len(basic_jisuanshi) + len(daiqie)])  # 切割符前面的整体加入列表
                    # 切割符加入列表
                    character_list.append(i)
                    # 将需要切割的式子迭代为切割符后面的式子
                    daiqie = daiqie[j - len(basic_jisuanshi) + len(daiqie) + 1:]
        # for循环执行完毕,说明对计算式的基本符号的分割完成,则 daiqie 中的结果是最后一次分割的分隔符后面的一个不需要再分割整体,故也需要加入列表
        character_list.append(daiqie)
        # 调用计算模块的计算功能进行计算,并将结果返回
        calculator = cal.Calculating()
        return calculator.calculating(character_list)


计算层(文件名:CalculatorCalculate.py)
import CalculatorSpecialCalculating as C

# 计算功能类
class Calculating:
    # 需要传入的是一个列表,列表是一个计算式按基本运算符(['+', '-', '*', '/', '%'])分割出来的列表
    def calculating(self, shiziliebiao):
        # 遍历列表中每个元素,判断其中是否有特殊运算;如果有,调用特殊运算模块的相应运算函数,进行运算,并将结果替换列表中对应的特殊运算
        for j in range(len(shiziliebiao)):
            i = str(shiziliebiao[j])
            if "log" in i:
                shiziliebiao[j] = C.log(i)
            elif '√' in i:
                shiziliebiao[j] = C.kaigeng(i)
            elif '!' in i:
                shiziliebiao[j] = C.jiecheng(i)
            elif 'cos' in i:
                shiziliebiao[j] = C.cos(i)
            elif 'sin' in i:
                shiziliebiao[j] = C.sin(i)
            elif 'tan' in i:
                shiziliebiao[j] = C.tan(i)
        # for 循环执行完成后,列表中一部分特殊运算经计算得出结果,另一部分特殊运算是eval()函数可以处理的计算
        # 将列表中的所有字符串连成一个完整的计算式,传入eval()函数中,就可以得出结果
        s = ""
        for i in shiziliebiao:
            s += str(i)
        # 返回计算结果
        return eval(s)

特殊计算处理层(文件名:CalculatorSpecialCalculating.py)
import math as m


# 对数,数据格式:底数log真数
def log(shizi):
    dishuANDzhengshu = shizi.split('log', 1)
    dishu = float(dishuANDzhengshu[0])
    zhengshu = float(dishuANDzhengshu[1])
    return m.log(zhengshu, dishu)


# 开平方,数据格式:√被开发数
def kaigeng(shizi):
    gendishu = shizi[1:]
    return eval(gendishu + "**0.5")


# 阶乘,数据格式:正整数!
def jiecheng(shizi):
    return m.factorial(int(shizi[:-1]))

# 三角函数,接收数据的单位为:角度
def sin(shizi):
    return m.sin(m.radians(float(shizi[3:])))


def cos(shizi):
    return m.cos(m.radians(float(shizi[3:])))


def tan(shizi):
    return m.tan(m.radians(float(shizi[3:])))


调用层(文件名:CalculatorInterface.py)
import CalculatorDataConller as cdc


def calculating(jisuanshi):
    controller = cdc.Controller()
    try:
        result = controller.processingData1(jisuanshi)
    except:
        return "错误"
    return result

# 测试
jisuanshi = '(2+6)*2+2log4+2**2+(2**2)**2-cos90+sin90+3!+3//2+50%40'
result = calculating(jisuanshi)
print(result) #结果 56

源码文件

只需要将文件拷贝到一个python项目的同一个文件夹下就可以使用
点击此处下载

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/993703.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号