利用python的eval()函数实现控制台计算器,并使用pyinstaller打包exe

与JavaScript中的eval函数类似,python中的eval函数也可以将字符串转换为代码执行。这一特性十分适合编写一个支持表达式输入的计算器。今天老师布置一个课后作业,设计一个计算器,设计要求是用控制台或GUI编写计算器程序,支持运算优先级,识别正负号,并且可以利用上次计算结果继续运算。于是我就想到了python语言,脑子里蹦出一个eval函数。进行其实后来才知道老师的本意是要我们做一个有限状态机,分析出计算机的各个状态,然后编程实习。但他事先又没说,于是我就曲解了。写下两行代码就初步实现了:

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

运行结果如下:


但是这样做有一个致命缺点,eval函数可以解析任何字符串作为命令,这就意味着可以导入os库后进行文件操作,这样的权限是万万不可以给的,况且也没有进行异常处理,输入一个非法表达式就会报错退出。

因此,上正则表达进行语法检查,判断新表达式 / 继续运算,造函数,强行装逼。

从2行代码深入浅出就得到了一下100行。
程序定义了2个全局变量:str型exprs,用于存储输入的字符串,sum保存上次计算结果
BracketUnbalanceCheck(str_in)函数用来检测括号的平衡
CyntaxErrorCheck(str_in)函数进行语法检测,判断是否包含 a-zA-Z<>,.?~!@#$%"这些字符,函数内使用了正则表达式来匹配

然后针对继续上次结果计算还是使用新表达计算,分别编写了两个函数:ContinueCompute()和NewCompute().

在main()中实现字符串的输入,调用上述两个语法检查函数进行合法性检查,再根据表达式的第一位是否为运算符,分配给ContinueCompute()或NewCompute()进行计算输出。在这两个函数中,还使用了try except语句进行了异常检测,主要防止0除。

至此,一个“玩不坏”的程序就完成了。

我们自嘲说,自己用的程序只要几行就可以了,但是写给用户用,就需要数十倍的规模,因为他们总能碰到奇形怪状的问题。

完整的代码如下:

#!/usr/bin/env python 
# -*- coding: cp936 -*-

#**********calculator.py***********
#功能描述:支持+-×/,指数运算(^),
#          支持包含括号的长表达式输入
#作者:南理工 电光学院
#      沈国锋 
#******2016/10/29 夜, 于30舍********
#*********CopyRight(c) @2016********
import re
exprs=''
sum=0
def PrintLicense():
    print("\
    calculator.py,Code With Python3.4\n\
    **********控制台计算器***********\n\
    ·支持+-×/运算,指数运算(^),\n\
    ·支持包含括号的长表达式输入\n\
    ·自动识别连续运算或以新表达式运算\n\
    ·完备的异常信息提示与处理\n\
    ********2016/10/29 夜, 于30舍*****\n\
    ********CopyRight(c) 2016********\n\
    ")
#BracketUnbalanceCheck(str_in):括号平衡检测函数,若不平衡,打印提示信息并返回1
#输入参数:str_in 需要检查的字符串
#返回值:括号不平衡返回1,否则返回-1
def BracketUnbalanceCheck(str_in):
    num=0
    for i in str_in:
        if i=='(':
            num+=1
        elif i==')':
            num-=1
    if num!=0:#括号不平衡
        print("错误01:输入的括号不平衡,请重新输入\n")
        return 1
    else:#括号平衡
        return -1
    
#CyntaxErrorCheck(str_in):语法检测函数,检测是否包含 a-zA-Z<>,.?~!@#$%";:这些字符
#输入参数:需要检查的字符串
def CharErrorCheck(str_in):
    if re.findall(r'[&a-zA-Z<>,?~!@#$%";:]',str_in):#正则表达式校验输入字符串的合法性
        print('错误02:表达式包含非法字符,请重新输入\n')
        return 1
    else:
        return -1
    
#InputExpression()函数,要求输入表达式,然后进行括号平衡检查和
#字符串合法性的初步检查,不合法则要求继续输入,直到正确为止
#然后通过判断表达式开始的符号是不是运算符,来判断继续运算还是开始新式运算
#无输入值,直接操作全局变量exprs
#返回字符串'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:
        #print("continue")
        return 'continue'
    else:
        #print('new')
        return 'new'
    
#函数ContinueCompute():接着上次的值继续计算。例如输入+1*2
#无输入输出值,直接操作全局变量exprs和sum
def ContinueCompute():
    global exprs
    global sum
    exprs=exprs.replace('^','**') #将^替换为**
    exprs=str(sum)+exprs
    try:
        sum=eval(exprs)
        print(exprs)
        print("="+str(sum))
    except SyntaxError:
        print("错误03:[终极错误]续上次结果计算时出现语法错误,程序返回\n")
    except ZeroDivisionError:
        print("错误05:除数不能为0,程序返回\n")
        
#函数NewCompute():开始一个新的表达式计算,例如(1+2)*2
#没有输入输出值,直接修改全局变量exprs和sum        
def NewCompute():
    global exprs
    global sum
    #print('当前字符串'+exprs)
    exprs=exprs.replace('^','**') #将^替换为**
    try:
        sum=eval(exprs)
        print(exprs)
        print("="+str(sum))
    except SyntaxError:
        print("错误04:[终极错误]使用新表达式进行计算时出现语法错误,程序返回\n")
    except ZeroDivisionError:
        print("错误05:除数不能为0,程序返回\n")
def main():
    global exprs
    '''sum=0
    exprs=input("输入表达式:")
    re.sub(r'^\^$', '**', exprs) #将^替换为**
    
    while CharErrorCheck(exprs) or BracketUnbalanceCheck(exprs):#直到得到一个合法的表达式
        exprs=input("输入表达式:\n")

    while True:
        try:
            s=eval(exprs)
            print(str(s))
        except SyntaxError:
            print("语法错误")
    '''
    PrintLicense()
    while True:
        exprs=input("输入表达式:")
        flag=InputExpression()
        if flag=='new':
            NewCompute()
        else:
            ContinueCompute()
    end
        
main()

为了在没有python环境的机器上也能够运行这个代码,还需要打包成exe。

目前python中常用的打包程序有pywin32和Pyinstaller,据网上说,后者更加方便。所以就使用这个啦。

按照pyinstaler可以使用pip,pip是python的一个包安装工具,按照python时会默认安装,就在python/scripts目录下,可以找到一个pip.exe文件。打开命令行程序,用cd命令转换到该目录后,键入

pip install pyinstaller

程序会自动下载所需的包,不出一分钟就安装成功了。

安装后pyinstaller也在scripts目录下

使用pyinstaller的命令参数如下:

F, --onefile produce a single file deployment (see below).
-D, --onedir produce a single directory deployment (default).
-K, --tk include TCL/TK in the deployment.
-a, --ascii do not include encodings. The default (on Python versions with unicode support) is now to include all encodings.
-d, --debug use debug (verbose) versions of the executables.
-w, --windowed, --noconsole
  Use the Windows subsystem executable, which does not open the console when the program is launched. (Windows only)
-c, --nowindowed, --console
  Use the console subsystem executable. This is the default. (Windows only)
-s, --strip the executable and all shared libraries will be run through strip. Note that cygwin's strip tends to render normal Win32 dlls unusable.
-X, --upx if you have UPX installed (detected by Configure), this will use it to compress your executable (and, on Windows, your dlls). See note below.
-o DIR, --out=DIR
  create the spec file in directory. If not specified, and the current directory is Installer's root directory, an output subdirectory will be created. Otherwise the current directory is used.
-p DIR, --paths=DIR
  set base path for import (like using PYTHONPATH). Multiple directories are allowed, separating them with the path separator (';' under Windows, ':' under Linux), or using this option multiple times.
--icon=<FILE.ICO>
  add file.ico to the executable's resources. (Windows only)
--icon=<FILE.EXE,N>
  add the n-th incon in file.exe to the executable's resources. (Windows only)
-v FILE, --version=FILE
  add verfile as a version resource to the executable. (Windows only)
-n NAME, --name=NAME
  optional name to assign to the project (from which the spec file name is generated). If omitted, the basename of the (first) script is used.

翻译成中文就是:

-F    制作独立的可执行程序
-D    制作出的档案存放在同一个文件夹下(默认值)

-K    包含TCL/TK(对于使用了TK的,最好加上这个选项,否则在未安装TK的电脑上无法运行)
-w     制作窗口程序
-c    制作命令行程序(默认)
-X    制作使用UPX压缩过的可执行程序(推荐使用这个选项,需要下载UPX包,解压后upx.exe放在Python(非PyInstaller)安装目录下,下载upx308w.zip

-o DIR  指定输出SPEC文件路径(这也决定了最后输出的exe文件路径)
--icon=[ICO文件路径] 指定程序图标
-v [指定文件] 指定程序版本信息
-n [指定程序名] 指定程序名称

一个典型的命令是
pyinstaller -F calculator.py

这时的图标是默认的python大蟒蛇,修改图标需要使用icon参数。
使用icon参数设置图标:
在win平台下,需要使用多个不同分辨率的ico图片,包括128×128 64 48 32 16,注意分辨率顺序从大到小,否则不能正常显示。制作ico文件可以使用脚本工具png2ico来实现。命令如下:
  1. png2ico myicon.ico icon_128x128.png icon_64x64.png icon_48x48.png icon_32x32.png icon_16x16.png   

最后得到的exe文件:

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值