首页 > 代码库 > python学习- 常用模块与re正则

python学习- 常用模块与re正则

开发一个简单的python计算器

  1. 实现加减乘除及拓号优先级解析
  2. 用户输入 1 - 2 * ( (60-30 +(-40/5) * (9-2*5/3 + 7 /3*99/4*2998 +10 * 568/14 )) - (-4*3)/ (16-3*2) )等类似公式后,必须自己解析里面的(),+,-,*,/符号和公式(不能调用eval等类似功能偷懒实现),运算后得出结果,结果必须与真实的计算器所得出的结果一致
技术分享
  1 import sys
  2 import re
  3  
  4 def welcome_func():
  5     """
  6     输入判断
  7     :param expression: 表达式
  8     :return: 返回有效表达式
  9     """
 10     welcome_str = "超级计算器"
 11     print(welcome_str.center(50,*),\n)  # 输出欢迎界面
 12     while True:
 13         iput = input("请输入你要计算的表达式[q:退出]:").strip()
 14         if iput == q:  # 退出计算
 15             sys.exit("bye-bye")
 16         elif len(iput) == 0:
 17             continue
 18         else:
 19             iput = re.sub(\s*, ‘‘, iput)  # 去除空格
 20             return iput
 21  
 22 def chengchu(expression):
 23     """
 24     乘除运算
 25     :param expression: 表达式
 26     :return: 返回没有乘除的表达式/最终计算结果
 27     """
 28     val = re.search(\d+\.*\d*[\*\/]+[\+\-]?\d+\.*\d*, expression)  # 匹配乘除号
 29     if not val:  # 乘除号不存在,返回输入的表达式
 30         return expression
 31     data =  http://www.mamicode.com/re.search(\d+\.*\d*[\*\/]+[\+\-]?\d+\.*\d*, expression).group()  # 匹配乘除号
 32     if len(data.split(*)) > 1:  # 当可以用乘号分割,证明有乘法运算
 33         part1, part2 = data.split(*)  # 以乘号作为分割符
 34         value = http://www.mamicode.com/float(part1) * float(part2)  # 计算乘法
 35     else:
 36         part1, part2 = data.split(/)  # 用除号分割
 37         if float(part2) == 0:  # 如果分母为0,则退出计算
 38             sys.exit("计算过程中有被除数为0的存在,计算表达式失败!")
 39         value = http://www.mamicode.com/float(part1) / float(part2)  # 计算除法
 40  
 41     #print("计算:%s=%s:" % (data,value) )
 42     # 获取第一个匹配到的乘除计算结果value,将value放回原表达式
 43     s1, s2 = re.split(\d+\.*\d*[\*\/]+[\+\-]?\d+\.*\d*, expression, 1)  # 分割表达式
 44     #print("上一个表达式:",expression)
 45     next_expression  = "%s%s%s" % (s1, value, s2)  # 将计算结果替换会表达式
 46     #print("下一个表达式%s" % next_expression)
 47     return chengchu(next_expression)  # 递归表达式
 48  
 49  
 50  
 51 def jiajian(expression):
 52     """
 53     加减运算
 54     :param expression: 表达式
 55     :return: 返回没有加减的表达式/最终计算结果
 56     """
 57     expression = expression.replace(+-,-)   # 替换表达式里的所有‘+-‘
 58     expression = expression.replace(--,+)   # 替换表达式里的所有‘--‘
 59     expression = expression.replace(-+,-)   # 替换表达式里的所有‘-+‘
 60     expression = expression.replace(++,+)   # 替换表达式里的所有‘++‘
 61     #print("处理特殊加减后的表达式:",expression)
 62     data = http://www.mamicode.com/re.search(\d+\.*\d*[\+\-]{1}\d+\.*\d*, expression)   # 匹配加减号
 63     if not data:   # 如果不存在加减号,则证明表达式已计算完成,返回最终结果
 64         return expression
 65     val = re.search([\-]?\d+\.*\d*[\+\-]{1}\d+\.*\d*, expression).group()
 66     if len(val.split(+)) > 1:   # 以加号分割成功,有加法计算
 67         part1, part2 = val.split(+)
 68         value = http://www.mamicode.com/float(part1) + float(part2)   # 计算加法
 69     elif val.startswith(-):  # 如果是已‘-‘开头则需要单独计算
 70         part1, part2, part3  = val.split(-)
 71         value = http://www.mamicode.com/-float(part2) - float(part3)  # 计算以负数开头的减法
 72     else:
 73         part1, part2 = val.split(-)
 74         value = http://www.mamicode.com/float(part1) - float(part2)  # 计算减法
 75      
 76     s1, s2 =  re.split([\-]?\d+\.*\d*[\+\-]{1}\d+\.*\d*, expression, 1)  # 分割表达式
 77     #print("计算%s=%s" % (val,value))
 78     next_expression = "%s%s%s" % (s1, value, s2)   # 将计算后的结果替换回表达式,生成下一个表达式
 79     #print("下一个表达式: ",next_expression)
 80     return jiajian(next_expression)  # 递归运算表达式
 81  
 82  
 83 def del_bracket(expression):
 84     """
 85     小括号去除运算
 86     :param expression: 表达式
 87     :return:
 88     """
 89     if not re.search(r\(([^()]+)\),expression):   # 判断小括号,如果不存在小括号,直接调用乘除,加减计算
 90         ret1 = chengchu(expression)
 91         ret2 = jiajian(ret1)
 92         return ret2   # 返回最终计算结果
 93     data = http://www.mamicode.com/re.search(r\(([^()]+)\), expression).group()  # 如果有小括号,匹配出优先级最高的小括号
 94     #print("获取表达式",data)
 95     data = http://www.mamicode.com/data.strip([\(\)])   # 剔除小括号
 96     ret1 = chengchu(data)   # 计算乘除
 97     #print("全部乘除计算完后的表达式:",ret1)
 98     ret2 = jiajian(ret1)   # 计算加减
 99     #print("全部加减计算结果:",ret2)
100     part1, replace_str, part2 = re.split(r\(([^()]+)\), expression, 1)  # 将小括号计算结果替换回表达式
101     expression = %s%s%s % (part1, ret2, part2)  # 生成新的表达式
102     return del_bracket(expression)  # 递归去小括号
103      
104  
105 if __name__ == "__main__":
106     try:
107         expression = welcome_func()   # 获取到的表达式
108         #expression = "-1+ 3 *(-3*2-2/-2+1)/2"
109         #expression = ‘1-2*((60-30+(-40.0/5)*(9-2*5/3+7/3*99/4*2998+10*568/14))-(-4*3)/(16-3*2))‘
110         reslut = eval(expression)   # 用eval计算验证
111         ret = del_bracket(expression)  # 用函数计算后得出的结果
112         reslut = float(reslut)
113         ret = float(ret)
114         if reslut == ret:   # 将两种方式计算的结果进行比较,如果相等,则计算正确,输出结果
115             print("eval计算结果:%s" % reslut)
116             print("表达式计算结果:%s" % ret)
117         else:   # 两种计算方式的结果不正确,提示异常,并返回两种方式的计算结果
118             print("计算结果异常,请重新检查!")
119             print("eval计算结果:%s" % reslut)
120             print("表达式计算结果:%s" % ret)
121     except(SyntaxError,ValueError,TypeError):   # 如果有不合法输出,则抛出错误
122         print("输入表达式不合法,请重新检查!")
123   
View Code

匿名函数:1. 没有名字 2:函数体自带return

f=lambda x,y,z=1:x+y+z
print(f)
print(f(1,2,3))

  

一、time模块

在Python中,通常有这几种方式来表示时间:

  • 时间戳(timestamp):通常来说,时间戳表示的是从1970年1月1日00:00:00开始按秒计算的偏移量。我们运行“type(time.time())”,返回的是float类型。
  • 格式化的时间字符串(Format String)
  • 结构化的时间(struct_time):struct_time元组共有9个元素共九个元素:(年,月,日,时,分,秒,一年中第几周,一年中第几天,夏令时)
技术分享
1 import time
2 #--------------------------我们先以当前时间为准,让大家快速认识三种形式的时间
3 print(time.time()) # 时间戳:1487130156.419527
4 print(time.strftime("%Y-%m-%d %X")) #格式化的时间字符串:‘2017-02-15 11:40:53‘
5 
6 print(time.localtime()) #本地时区的struct_time
7 print(time.gmtime())    #UTC时区的struct_time
例子1
技术分享
 1 # localtime([secs])
 2 # 将一个时间戳转换为当前时区的struct_time。secs参数未提供,则以当前时间为准。
 3 time.localtime()
 4 time.localtime(1473525444.037215)
 5 
 6 # gmtime([secs]) 和localtime()方法类似,gmtime()方法是将一个时间戳转换为UTC时区(0时区)的struct_time。
 7 
 8 # mktime(t) : 将一个struct_time转化为时间戳。
 9 print(time.mktime(time.localtime()))#1473525749.0
10 
11 
12 # strftime(format[, t]) : 把一个代表时间的元组或者struct_time(如由time.localtime()和
13 # time.gmtime()返回)转化为格式化的时间字符串。如果t未指定,将传入time.localtime()。如果元组中任何一个
14 # 元素越界,ValueError的错误将会被抛出。
15 print(time.strftime("%Y-%m-%d %X", time.localtime()))#2016-09-11 00:49:56
16 
17 # time.strptime(string[, format])
18 # 把一个格式化时间字符串转化为struct_time。实际上它和strftime()是逆操作。
19 print(time.strptime(2011-05-05 16:37:06, %Y-%m-%d %X))
20 #time.struct_time(tm_year=2011, tm_mon=5, tm_mday=5, tm_hour=16, tm_min=37, tm_sec=6,
21 #  tm_wday=3, tm_yday=125, tm_isdst=-1)
22 #在这个函数中,format默认为:"%a %b %d %H:%M:%S %Y"。
例子2

二、random模块

技术分享
 1 import random
 2  
 3 print(random.random())#(0,1)----float    大于0且小于1之间的小数
 4  
 5 print(random.randint(1,3))  #[1,3]    大于等于1且小于等于3之间的整数
 6  
 7 print(random.randrange(1,3)) #[1,3)    大于等于1且小于3之间的整数
 8  
 9 print(random.choice([1,23,[4,5]]))#1或者23或者[4,5]
10  
11 print(random.sample([1,23,[4,5]],2))#列表元素任意2个组合
12  
13 print(random.uniform(1,3))#大于1小于3的小数,如1.927109612082716 
14  
15  
16 item=[1,3,5,7,9]
17 random.shuffle(item) #打乱item的顺序,相当于"洗牌"
18 print(item)
例子
技术分享
 1 import random
 2 def make_code(n):
 3     res=‘‘
 4     for i in range(n):
 5         s1=chr(random.randint(65,90))
 6         s2=str(random.randint(0,10))
 7         res+=random.choice([s1,s2])
 8     return res
 9 
10 print(make_code(9))
11 
12 生成随机验证码
生成随机验证码

三、os模块

os模块是与操作系统交互的一个接口

技术分享
 1 os.getcwd() 获取当前工作目录,即当前python脚本工作的目录路径
 2 os.chdir("dirname")  改变当前脚本工作目录;相当于shell下cd
 3 os.curdir  返回当前目录: (.)
 4 os.pardir  获取当前目录的父目录字符串名:(..)
 5 os.makedirs(dirname1/dirname2)    可生成多层递归目录
 6 os.removedirs(dirname1)    若目录为空,则删除,并递归到上一级目录,如若也为空,则删除,依此类推
 7 os.mkdir(dirname)    生成单级目录;相当于shell中mkdir dirname
 8 os.rmdir(dirname)    删除单级空目录,若目录不为空则无法删除,报错;相当于shell中rmdir dirname
 9 os.listdir(dirname)    列出指定目录下的所有文件和子目录,包括隐藏文件,并以列表方式打印
10 os.remove()  删除一个文件
11 os.rename("oldname","newname")  重命名文件/目录
12 os.stat(path/filename)  获取文件/目录信息
13 os.sep    输出操作系统特定的路径分隔符,win下为"\\",Linux下为"/"
14 os.linesep    输出当前平台使用的行终止符,win下为"\t\n",Linux下为"\n"
15 os.pathsep    输出用于分割文件路径的字符串 win下为;,Linux下为:
16 os.name    输出字符串指示当前使用平台。win->nt; Linux->posix
17 os.system("bash command")  运行shell命令,直接显示
18 os.environ  获取系统环境变量
19 os.path.abspath(path)  返回path规范化的绝对路径
20 os.path.split(path)  将path分割成目录和文件名二元组返回
21 os.path.dirname(path)  返回path的目录。其实就是os.path.split(path)的第一个元素
22 os.path.basename(path)  返回path最后的文件名。如何path以/或\结尾,那么就会返回空值。即os.path.split(path)的第二个元素
23 os.path.exists(path)  如果path存在,返回True;如果path不存在,返回False
24 os.path.isabs(path)  如果path是绝对路径,返回True
25 os.path.isfile(path)  如果path是一个存在的文件,返回True。否则返回False
26 os.path.isdir(path)  如果path是一个存在的目录,则返回True。否则返回False
27 os.path.join(path1[, path2[, ...]])  将多个路径组合后返回,第一个绝对路径之前的参数将被忽略
28 os.path.getatime(path)  返回path所指向的文件或者目录的最后存取时间
29 os.path.getmtime(path)  返回path所指向的文件或者目录的最后修改时间
30 os.path.getsize(path) 返回path的大小
os模块用法
技术分享
 1 os路径处理
 2 #方式一:推荐使用
 3 import os
 4 #具体应用
 5 import os,sys
 6 possible_topdir = os.path.normpath(os.path.join(
 7     os.path.abspath(__file__),
 8     os.pardir, #上一级
 9     os.pardir,
10     os.pardir
11 ))
12 sys.path.insert(0,possible_topdir)
13 
14 
15 #方式二:不推荐使用
16 os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
使用方法

四、sys模块

技术分享
1 sys.argv           命令行参数List,第一个元素是程序本身路径
2 sys.exit(n)        退出程序,正常退出时exit(0)
3 sys.version        获取Python解释程序的版本信息
4 sys.maxint         最大的Int值
5 sys.path           返回模块的搜索路径,初始化时使用PYTHONPATH环境变量的值
6 sys.platform       返回操作系统平台名称
sys用法
技术分享
 1 def progress(percent,width=50): #51
 2     if percent >= 100:
 3         # print(‘\r[%s] 100%%‘ %(width*‘#‘))
 4         percent=100
 5     show_str=([%%-%ds] %width) %(int(width*percent/100)*#)
 6     print(\r%s %d%% %(show_str,percent),file=sys.stdout,flush=True,end=‘‘)
 7 #
 8 total_size=1025121
 9 recv_size=0
10 
11 while recv_size < total_size:
12     time.sleep(0.01) #模拟下载的网络延迟
13     recv_size+=1024
14     recv_per=int(100*recv_size/total_size)
15     progress(recv_per,width=10)
例子:模拟进度条

五、shutil模块

高级的 文件、文件夹、压缩包 处理模块

shutil.copyfileobj(fsrc, fdst[, length])
将文件内容拷贝到另一个文件中

1 import shutil
2  
3 shutil.copyfileobj(open(‘old.xml‘,‘r‘), open(‘new.xml‘, ‘w‘))

 

shutil.copyfile(src, dst)
拷贝文件

1 shutil.copyfile(‘f1.log‘, ‘f2.log‘) #目标文件无需存在

 

shutil.copymode(src, dst)
仅拷贝权限。内容、组、用户均不变

1 shutil.copymode(‘f1.log‘, ‘f2.log‘) #目标文件必须存在

 

shutil.copystat(src, dst)
仅拷贝状态的信息,包括:mode bits, atime, mtime, flags

1 shutil.copystat(‘f1.log‘, ‘f2.log‘) #目标文件必须存在

 

shutil.copy(src, dst)
拷贝文件和权限

1 import shutil
2  
3 shutil.copy(‘f1.log‘, ‘f2.log‘)

 

shutil.copy2(src, dst)
拷贝文件和状态信息

1 import shutil
2  
3 shutil.copy2(‘f1.log‘, ‘f2.log‘)

 

shutil.ignore_patterns(*patterns)
shutil.copytree(src, dst, symlinks=False, ignore=None)
递归的去拷贝文件夹

1 import shutil
2  
3 shutil.copytree(‘folder1‘, ‘folder2‘, ignore=shutil.ignore_patterns(‘*.pyc‘, ‘tmp*‘)) #目标目录不能存在,注意对folder2目录父级目录要有可写权限,ignore的意思是排除 
技术分享 拷贝软连接

 

shutil.rmtree(path[, ignore_errors[, one rror]])
递归的去删除文件

1 import shutil
2  
3 shutil.rmtree(‘folder1‘)

 

shutil.move(src, dst)
递归的去移动文件,它类似mv命令,其实就是重命名。

1 import shutil
2  
3 shutil.move(‘folder1‘, ‘folder3‘)

 

shutil.make_archive(base_name, format,...)

创建压缩包并返回文件路径,例如:zip、tar

创建压缩包并返回文件路径,例如:zip、tar

  • base_name: 压缩包的文件名,也可以是压缩包的路径。只是文件名时,则保存至当前目录,否则保存至指定路径,
    如 data_bak                       =>保存至当前路径
    如:/tmp/data_bak =>保存至/tmp/
  • format: 压缩包种类,“zip”, “tar”, “bztar”,“gztar”
  • root_dir: 要压缩的文件夹路径(默认当前目录)
  • owner: 用户,默认当前用户
  • group: 组,默认当前组
  • logger: 用于记录日志,通常是logging.Logger对象
  • 技术分享
    1 #将 /data 下的文件打包放置当前程序目录
    2 import shutil
    3 ret = shutil.make_archive("data_bak", gztar, root_dir=/data)
    4   
    5   
    6 #将 /data下的文件打包放置 /tmp/目录
    7 import shutil
    8 ret = shutil.make_archive("/tmp/data_bak", gztar, root_dir=/data)
    例子

     

shutil 对压缩包的处理是调用 ZipFile 和 TarFile 两个模块来进行的,详细:

技术分享 zipfile压缩解压缩
技术分享 tarfile压缩解压缩

 

六、 json&pickle模块

技术分享
 1 import json
 2  
 3 dic={name:alvin,age:23,sex:male}
 4 print(type(dic))#<class ‘dict‘>
 5  
 6 j=json.dumps(dic)
 7 print(type(j))#<class ‘str‘>
 8  
 9  
10 f=open(序列化对象,w)
11 f.write(j)  #-------------------等价于json.dump(dic,f)
12 f.close()
13 #-----------------------------反序列化<br>
14 import json
15 f=open(序列化对象)
16 data=http://www.mamicode.com/json.loads(f.read())#  等价于data=http://www.mamicode.com/json.load(f)
json序化例子
技术分享
import json
#dct="{‘1‘:111}"#json 不认单引号
#dct=str({"1":111})#报错,因为生成的数据还是单引号:{‘one‘: 1}

dct={"1":"111"}
print(json.loads(dct))

#conclusion:
#        无论数据是怎样创建的,只要满足json格式,就可以json.loads出来,不一定非要dumps的数据才能loads
注意
技术分享
 1 import pickle
 2  
 3 dic={name:alvin,age:23,sex:male}
 4  
 5 print(type(dic))#<class ‘dict‘>
 6  
 7 j=pickle.dumps(dic)
 8 print(type(j))#<class ‘bytes‘>
 9  
10  
11 f=open(序列化对象_pickle,wb)#注意是w是写入str,wb是写入bytes,j是‘bytes‘
12 f.write(j)  #-------------------等价于pickle.dump(dic,f)
13  
14 f.close()
15 #-------------------------反序列化
16 import pickle
17 f=open(序列化对象_pickle,rb)
18  
19 data=http://www.mamicode.com/pickle.loads(f.read())#  等价于data=http://www.mamicode.com/pickle.load(f)
20  
21  
22 print(data[age])
pickle例子

 

python学习- 常用模块与re正则