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个组合 可能是 1和23 也能使 23 和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 print(random.sample([1,'23',[4,5]],2)) 3 print(random.uniform(1,3)) 4 5 6 item=[1,3,5,7,9] 7 random.shuffle(item) 8 print(item) 9 10 11 ##随机生成验证码 12 def make_code(n): #生成长度为n位的验证码 13 res='' 14 for i in range(n): 15 s1=str(random.randint(0,9)) #产生0 - 9 的随机数字 16 s2=chr(random.randint(65,90)) #产生65 - 90 的随机数字所代表的acsii码的字符 65-90是大写字母 17 res+=random.choice([s1,s2]) #随机选一个 18 return res 19 print(make_code(10)) #生成10位数字+大写字母组合成的随机验证码
##---结果---
[1, [4, 5]] 1.4714607001467908 [9, 3, 1, 5, 7] IIK7Z9J93Y
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下为" ",Linux下为" " 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的大小
在Linux和Mac平台上,该函数会原样返回path,在windows平台上会将路径中所有字符转换为小写,并将所有斜杠转换为饭斜杠。
>>> os.path.normcase('c:/windows\system32\')
'c:\windows\system32\'
规范化路径,如..和/
>>> os.path.normpath('c://windows\System32\../Temp/')
'c:\windows\Temp'
>>> a='/Users/jieli/test1/\a1/\\aa.py/../..'
>>> print(os.path.normpath(a))
/Users/jieli/test1
os路径处理
#方式一:推荐使用
import os #具体应用 import os,sys possible_topdir = os.path.normpath(os.path.join( os.path.abspath(__file__), os.pardir, #上一级 os.pardir, os.pardir )) sys.path.insert(0,possible_topdir)
#方式二:不推荐使用
os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
1 import os 2 3 # print(os.listdir('.')) #当前目录文件 4 5 # print(os.stat('m1.py').st_size) 6 7 # print(os.sep) #路径分隔符 8 # print(os.linesep) #换行符 9 # print(os.pathsep) #文件路径分隔符 10 11 # print([os.sep,os.linesep,os.pathsep]) #用列表的形式展示 12 13 # res=os.system('dir .') #当前目录下有什么子文件 14 # print('====?>',res) 15 16 # print(os.path.dirname(r'C:acda.txt')) 17 # print(os.path.basename(r'C:acda.txt')) 18 # print(os.path.split(r'C:acda.txt')) 19 20 # print(os.stat('m1.py').st_atime) 21 # print(os.stat('m1.py').st_size) 22 # print(os.path.getsize('m1.py')) 23 24 25 # print(os.path.join('C:\','a','b','c','d.txt')) #拼接路径,如果有多个绝对路径,最后一个绝对路径之前的全部忽略 26 # print(os.path.join('C:\','a','b','D:\','c','d.txt')) 27 28 # print(os.path.normcase('c:/wiNdows\system32\') ) #路径格式转换,对于win系统,左斜杠变为右斜杠,大写字母变为小写字母 29 30 # print(os.path.normpath('c://wIndows\System32\../Temp/') ) #..代表上级目录 31 #--结果 c:wIndowsTemp
32 # a='/Users/jieli/test1/\a1/\\aa.py/../..' 33 # print(os.path.normpath(a)) 34 #--结果 Usersjieli est1 35 36 print(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) 37 38 BASE_DIR=os.path.normpath(os.path.join( 39 os.path.abspath(__file__), 40 '..', 41 '..' 42 ) 43 ) 44 print(BASE_DIR)
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 返回操作系统平台名称
打印进度条
1 #=========知识储备========== 2 #进度条的效果 3 [# ] 4 [## ] 5 [### ] 6 [#### ] 7 8 #指定宽度 9 print('[%-15s]' %'#') 10 print('[%-15s]' %'##') 11 print('[%-15s]' %'###') 12 print('[%-15s]' %'####') 13 14 #打印% 15 print('%s%%' %(100)) #第二个%号代表取消第一个%的特殊意义 16 17 #可传参来控制宽度 18 print('[%%-%ds]' %50) #[%-50s] 19 print(('[%%-%ds]' %50) %'#') 20 print(('[%%-%ds]' %50) %'##') 21 print(('[%%-%ds]' %50) %'###') 22 23 24 #=========实现打印进度条函数========== 25 import sys 26 import time 27 28 def progress(percent,width=50): 29 if percent >= 1: 30 percent=1 31 show_str=('[%%-%ds]' %width) %(int(width*percent)*'#') 32 print(' %s %d%%' %(show_str,int(100*percent)),file=sys.stdout,flush=True,end='') 33 34 35 #=========应用========== 36 data_size=1025 37 recv_size=0 38 while recv_size < data_size: 39 time.sleep(0.1) #模拟数据的传输延迟 40 recv_size+=1024 #每次收1024 41 42 percent=recv_size/data_size #接收的比例 43 progress(percent,width=70) #进度条的宽度70 44 45 #打印进度条
1 ###模拟下载进度条 2 def progress(percent,width=50): #固定宽度 3 if percent >= 100: 4 # print(' [%s] 100%%' %(width*'#')) 5 percent=100 6 show_str=('[%%-%ds]' %width) %(int(width*percent/100)*'#') #固定长度,百分比的形式 7 print(' %s %d%%' %(show_str,percent),file=sys.stdout,flush=True,end='') 8 # 9 total_size=1025121 10 recv_size=0 11 12 while recv_size < total_size: 13 time.sleep(0.01) #模拟下载的网络延迟 14 recv_size+=1024 #传输速率 15 recv_per=int(100*recv_size/total_size) 16 progress(recv_per,width=10)
json&pickle模块
之前我们学习过用eval内置方法可以将一个字符串转成python对象,不过,eval方法是有局限性的,对于普通的数据类型,json.loads和eval都能用,但遇到特殊类型的时候,eval就不管用了,所以eval的重点还是通常用来执行一个字符串表达式,并返回表达式的值。
1 import json
2 x="[null,true,false,1]"
3 print(eval(x)) #报错,无法解析null类型,而json就可以
4 print(json.loads(x))
什么是序列化?
我们把对象(变量)从内存中变成可存储或传输的过程称之为序列化,在Python中叫pickling,在其他语言中也被称之为serialization,marshalling,flattening等等,都是一个意思。
为什么要序列化?
1:持久保存状态
需知一个软件/程序的执行就在处理一系列状态的变化,在编程语言中,'状态'会以各种各样有结构的数据类型(也可简单的理解为变量)的形式被保存在内存中。
内存是无法永久保存数据的,当程序运行了一段时间,我们断电或者重启程序,内存中关于这个程序的之前一段时间的数据(有结构)都被清空了。
在断电或重启程序之前将程序当前内存中所有的数据都保存下来(保存到文件中),以便于下次程序执行能够从文件中载入之前的数据,然后继续执行,这就是序列化。
具体的来说,你玩使命召唤闯到了第13关,你保存游戏状态,关机走人,下次再玩,还能从上次的位置开始继续闯关。或如,虚拟机状态的挂起等。
2:跨平台数据交互
序列化之后,不仅可以把序列化后的内容写入磁盘,还可以通过网络传输到别的机器上,如果收发的双方约定好实用一种序列化的格式,那么便打破了平台/语言差异化带来的限制,实现了跨平台数据交互。
反过来,把变量内容从序列化的对象重新读到内存里称之为反序列化,即unpickling。
如何序列化之json和pickle:
json
如果我们要在不同的编程语言之间传递对象,就必须把对象序列化为标准格式,比如XML,但更好的方法是序列化为JSON,因为JSON表示出来就是一个字符串,可以被所有语言读取,也可以方便地存储到磁盘或者通过网络传输。JSON不仅是标准格式,并且比XML更快,而且可以直接在Web页面中读取,非常方便。
内存中结构化数据 <-----> 格式JSON <----->字符串 <-----> 保存到文件中会基于网络传输
举例
1 import json 2 # dic={'name':'egon','age':18} #一个自定类型 3 4 # print(type(json.dumps(dic))) #导入模块 叫 json , 序列化,字典转成了字符串形式,使用 dumps转换 5 6 # with open('a.json','w') as f: #可以吧转换后的字符串写入到文件中 7 # f.write(json.dumps(dic)) 8 9 # with open('a.json','r') as f: #使用json读取文件 evel只是把字符串里的命令提取出来执行下,没有序列化的作用 10 # data=f.read() 11 # dic=json.loads(data) #取文件,相当于反序列化 12 # print(dic['name']) 13 14 # dic={'name':'egon','age':18} #原生字典 15 # json.dump(dic,open('b.json','w')) #序列化 dump 生成字符串 16 # print(json.load(open('b.json','r'))['name']) #反解序列化 字符串解析成字典 17 18 19 20 # with open('c.json','r') as f: 21 # data=f.read() 22 # #[null,true,false,1] 23 # eval(data) #evel只是把字符串里的命令提取出来执行下,没有序列化的作用
注意点
1 import json 2 #dct="{'1':111}"#json 不认单引号 3 #dct=str({"1":111})#报错,因为生成的数据还是单引号:{'one': 1} 4 5 dct='{"1":"111"}' 6 print(json.loads(dct)) 7 8 #conclusion: 9 # 无论数据是怎样创建的,只要满足json格式,就可以json.loads出来,不一定非要dumps的数据才能loads
pickle序列化
内存中结构化数据 <-----> 格式pickle <----->bytes类型 <-----> 保存到文件中会基于网络传输
Pickle的问题和所有其他编程语言特有的序列化问题一样,就是它只能用于Python,并且可能不同版本的Python彼此都不兼容,因此,只能用Pickle保存那些不重要的数据,不能成功地反序列化也没关系。
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=pickle.loads(f.read())# 等价于data=pickle.load(f) 20 21 22 print(data['age'])
1 #pickle序列化 2 import pickle 3 4 # dic={'name':'egon','age':18} 5 # 6 # print(pickle.dumps(dic)) 7 # with open('d.pkl','wb') as f: 8 # f.write(pickle.dumps(dic)) #序列化,将字典的形式转换成byte类型 9 10 # with open('d.pkl','rb') as f: 11 # dic=pickle.loads(f.read()) #反序列化 12 # print(dic['name']) 13 14 # dic={'name':'egon','age':18} 15 # pickle.dump(dic,open('e.pkl','wb')) 16 17 18 # print(pickle.load(open('e.pkl','rb'))['name']) 21 22 # 23 24 def func(): 25 print('from func') 26 28 # import json 29 # print(json.dumps(func)) #函数不是json对象 30 31 import pickle 32 # print(pickle.dumps(func)) #只要是放到内存里的东西都可以序列化 33 pickle.dump(func,open('func.pkl','wb')) 34 35 #################### 36 #pickle反序列化(基于内存中有这个地址才能反序列化) 37 import pickle 38 39 # def func(): 40 # print('反序列化的文件') 41 42 # pickle.dump(func,open('func.pkl','wb')) 43 # f=pickle.load(open('func.pkl','rb')) 44 # print(f) 45 46 47 # class Foo: 48 # pass 49 50 51 # obj1=Foo() 52 # obj2=Foo() 53 # print(obj1 is obj2) 54 55 # pickle.dump(obj1,open('class.pkl','wb')) 56 57 58 # import pickle 59 # pickle.load(open('class.pkl','rb')) #反序列化 60 61 62 63 # l1=list() 64 # l2=list() 65 # print(type(l1)) 66 # print(type(l2))
shelve模块
shelve模块比pickle模块简单,只有一个open函数,返回类似字典的对象,可读可写;
key必须为字符串,而值可以是python所支持的数据类型
1 import shelve 2 3 f=shelve.open(r'sheve.txt') 4 # f['stu1_info']={'name':'egon','age':18,'hobby':['piao','smoking','drinking']} 5 # f['stu2_info']={'name':'gangdan','age':53} 6 # f['school_info']={'website':'http://www.pypy.org','city':'beijing'} 7 8 print(f['stu1_info']['hobby']) 9 f.close()
小练习 计算器
开发一个简单的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 #!/usr/bin/env python 2 # -*- coding:utf-8 -*- 3 """ 4 该计算器思路: 5 1、递归寻找表达式中只含有 数字和运算符的表达式,并计算结果 6 2、由于整数计算会忽略小数,所有的数字都认为是浮点型操作,以此来保留小数 7 使用技术: 8 1、正则表达式 9 2、递归 10 11 执行流程如下: 12 ******************** 请计算表达式: 1 - 2 * ( (60-30 +(-40.0/5) * (9-2*5/3 + 7 /3*99/4*2998 +10 * 568/14 )) - (-4*3)/ (16-3*2) ) ******************** 13 before: ['1-2*((60-30+(-40.0/5)*(9-2*5/3+7/3*99/4*2998+10*568/14))-(-4*3)/(16-3*2))'] 14 -40.0/5=-8.0 15 after: ['1-2*((60-30+-8.0*(9-2*5/3+7/3*99/4*2998+10*568/14))-(-4*3)/(16-3*2))'] 16 ========== 上一次计算结束 ========== 17 before: ['1-2*((60-30+-8.0*(9-2*5/3+7/3*99/4*2998+10*568/14))-(-4*3)/(16-3*2))'] 18 9-2*5/3+7/3*99/4*2998+10*568/14=173545.880953 19 after: ['1-2*((60-30+-8.0*173545.880953)-(-4*3)/(16-3*2))'] 20 ========== 上一次计算结束 ========== 21 before: ['1-2*((60-30+-8.0*173545.880953)-(-4*3)/(16-3*2))'] 22 60-30+-8.0*173545.880953=-1388337.04762 23 after: ['1-2*(-1388337.04762-(-4*3)/(16-3*2))'] 24 ========== 上一次计算结束 ========== 25 before: ['1-2*(-1388337.04762-(-4*3)/(16-3*2))'] 26 -4*3=-12.0 27 after: ['1-2*(-1388337.04762--12.0/(16-3*2))'] 28 ========== 上一次计算结束 ========== 29 before: ['1-2*(-1388337.04762--12.0/(16-3*2))'] 30 16-3*2=10.0 31 after: ['1-2*(-1388337.04762--12.0/10.0)'] 32 ========== 上一次计算结束 ========== 33 before: ['1-2*(-1388337.04762--12.0/10.0)'] 34 -1388337.04762--12.0/10.0=-1388335.84762 35 after: ['1-2*-1388335.84762'] 36 ========== 上一次计算结束 ========== 37 我的计算结果: 2776672.69524 38 """ 39 40 41 import re 42 43 44 def compute_mul_div(arg): 45 """ 操作乘除 46 :param expression:表达式 47 :return:计算结果 48 """ 49 50 val = arg[0] 51 mch = re.search('d+.*d*[*/]+[+-]?d+.*d*', val) 52 if not mch: 53 return 54 content = re.search('d+.*d*[*/]+[+-]?d+.*d*', val).group() 55 56 if len(content.split('*'))>1: 57 n1, n2 = content.split('*') 58 value = float(n1) * float(n2) 59 else: 60 n1, n2 = content.split('/') 61 value = float(n1) / float(n2) 62 63 before, after = re.split('d+.*d*[*/]+[+-]?d+.*d*', val, 1) 64 new_str = "%s%s%s" % (before,value,after) 65 arg[0] = new_str 66 compute_mul_div(arg) 67 68 69 def compute_add_sub(arg): 70 """ 操作加减 71 :param expression:表达式 72 :return:计算结果 73 """ 74 while True: 75 if arg[0].__contains__('+-') or arg[0].__contains__("++") or arg[0].__contains__('-+') or arg[0].__contains__("--"): 76 arg[0] = arg[0].replace('+-','-') 77 arg[0] = arg[0].replace('++','+') 78 arg[0] = arg[0].replace('-+','-') 79 arg[0] = arg[0].replace('--','+') 80 else: 81 break 82 83 if arg[0].startswith('-'): 84 arg[1] += 1 85 arg[0] = arg[0].replace('-','&') 86 arg[0] = arg[0].replace('+','-') 87 arg[0] = arg[0].replace('&','+') 88 arg[0] = arg[0][1:] 89 val = arg[0] 90 mch = re.search('d+.*d*[+-]{1}d+.*d*', val) 91 if not mch: 92 return 93 content = re.search('d+.*d*[+-]{1}d+.*d*', val).group() 94 if len(content.split('+'))>1: 95 n1, n2 = content.split('+') 96 value = float(n1) + float(n2) 97 else: 98 n1, n2 = content.split('-') 99 value = float(n1) - float(n2) 100 101 before, after = re.split('d+.*d*[+-]{1}d+.*d*', val, 1) 102 new_str = "%s%s%s" % (before,value,after) 103 arg[0] = new_str 104 compute_add_sub(arg) 105 106 107 def compute(expression): 108 """ 操作加减乘除 109 :param expression:表达式 110 :return:计算结果 111 """ 112 inp = [expression,0] 113 114 # 处理表达式中的乘除 115 compute_mul_div(inp) 116 117 # 处理 118 compute_add_sub(inp) 119 if divmod(inp[1],2)[1] == 1: 120 result = float(inp[0]) 121 result = result * -1 122 else: 123 result = float(inp[0]) 124 return result 125 126 127 def exec_bracket(expression): 128 """ 递归处理括号,并计算 129 :param expression: 表达式 130 :return:最终计算结果 131 """ 132 # 如果表达式中已经没有括号,则直接调用负责计算的函数,将表达式结果返回,如:2*1-82+444 133 if not re.search('(([+-*/]*d+.*d*){2,})', expression): 134 final = compute(expression) 135 return final 136 # 获取 第一个 只含有 数字/小数 和 操作符 的括号 137 # 如: 138 # ['1-2*((60-30+(-40.0/5)*(9-2*5/3+7/3*99/4*2998+10*568/14))-(-4*3)/(16-3*2))'] 139 # 找出:(-40.0/5) 140 content = re.search('(([+-*/]*d+.*d*){2,})', expression).group() 141 142 # 分割表达式,即: 143 # 将['1-2*((60-30+(-40.0/5)*(9-2*5/3+7/3*99/4*2998+10*568/14))-(-4*3)/(16-3*2))'] 144 # 分割更三部分:['1-2*((60-30+( (-40.0/5) *(9-2*5/3+7/3*99/4*2998+10*568/14))-(-4*3)/(16-3*2))'] 145 before, nothing, after = re.split('(([+-*/]*d+.*d*){2,})', expression, 1) 146 147 print 'before:',expression 148 content = content[1:len(content)-1] 149 150 # 计算,提取的表示 (-40.0/5),并活的结果,即:-40.0/5=-8.0 151 ret = compute(content) 152 153 print '%s=%s' %( content, ret) 154 155 # 将执行结果拼接,['1-2*((60-30+( -8.0 *(9-2*5/3+7/3*99/4*2998+10*568/14))-(-4*3)/(16-3*2))'] 156 expression = "%s%s%s" %(before, ret, after) 157 print 'after:',expression 158 print "="*10,'上一次计算结束',"="*10 159 160 # 循环继续下次括号处理操作,本次携带者的是已被处理后的表达式,即: 161 # ['1-2*((60-30+ -8.0 *(9-2*5/3+7/3*99/4*2998+10*568/14))-(-4*3)/(16-3*2))'] 162 163 # 如此周而复始的操作,直到表达式中不再含有括号 164 return exec_bracket(expression) 165 166 167 168 # 使用 __name__ 的目的: 169 # 只有执行 python index.py 时,以下代码才执行 170 # 如果其他人导入该模块,以下代码不执行 171 if __name__ == "__main__": 172 #print '*'*20,"请计算表达式:", "1 - 2 * ( (60-30 +(-40.0/5) * (9-2*5/3 + 7 /3*99/4*2998 +10 * 568/14 )) - (-4*3)/ (16-3*2) )" ,'*'*20 173 #inpp = '1 - 2 * ( (60-30 +(-40.0/5) * (9-2*5/3 + 7 /3*99/4*2998 +10 * 568/14 )) - (-4*3)/ (16-3*2) ) ' 174 inpp = "1-2*-30/-12*(-20+200*-3/-200*-300-100)" 175 #inpp = "1-5*980.0" 176 inpp = re.sub('s*','',inpp) 177 # 表达式保存在列表中 178 result = exec_bracket(inpp) 179 print result