pyday06
一、Python常用模块
1.正则表达式与re模块:
1)什么是正则:
正则就是用一些具有特殊含义的符号组合到一起(称为正则表达式)来描述字符或者字符串的方法。或者说:正则就是用来描述一类事物的规则。(在Python中)它内嵌在Python中,并通过 re 模块实现。正则表达式模式被编译成一系列的字节码,然后由用 C 编写的匹配引擎执行。
2)常用匹配模式:

import re print(re.findall('\w','abc123d_ef * | - =')) print(re.findall('\W','abc123d_ef * | - =')) print(re.findall('\s','abc12\n3d\t_ef * | - =')) print(re.findall('\S','abc12\n3d\t_ef * | - =')) print(re.findall('\d','abc12\n3d\t_ef * | - =')) print(re.findall('\D','abc12\n3d\t_ef * | - =')) # 运行结果: ['a', 'b', 'c', '1', '2', '3', 'd', '_', 'e', 'f'] [' ', '*', ' ', '|', ' ', '-', ' ', '='] ['\n', '\t', ' ', ' ', ' ', ' '] ['a', 'b', 'c', '1', '2', '3', 'd', '_', 'e', 'f', '*', '|', '-', '='] ['1', '2', '3'] ['a', 'b', 'c', '\n', 'd', '\t', '_', 'e', 'f', ' ', '*', ' ', '|', ' ', '-', ' ', '=']
import re print(re.findall('\n','hello elaine \n123')) print(re.findall('\t','hello elaine \t123')) print(re.findall('^h','hello elaine \n123')) print(re.findall('3$','hello elaine \n123')) 运行结果: ['\n'] ['\t'] ['h'] ['3']
#. print(re.findall('a.b','a1b')) #['a1b'] print(re.findall('a.b','a\nb')) #[] print(re.findall('a.b','a\nb',re.S)) #['a\nb'] print(re.findall('a.b','a\nb',re.DOTALL)) #['a\nb']同上一条意思一样 #* print(re.findall('ab*','bbbbbbb')) #[] print(re.findall('ab*','a')) #['a'] print(re.findall('ab*','abbbb')) #['abbbb'] #? 匹配0个或者1个 print(re.findall('ab?','a')) #['a'] print(re.findall('ab?','abbb')) #['ab'] #匹配所有包含小数在内的数字 print(re.findall('\d+\.?\d*',"asdfasdf123as1.13dfa12adsf1asdf3")) #['123', '1.13', '12', '1', '3'] #.*默认为贪婪匹配 print(re.findall('a.*b','a1b22222222b')) #['a1b22222222b'] #.*?为非贪婪匹配:推荐使用 print(re.findall('a.*?b','a1b22222222b')) #['a1b'] #+ 匹配1个或者多个 print(re.findall('ab+','a')) #[] print(re.findall('ab+','abbb')) #['abbb'] #{n,m} print(re.findall('ab{2}','abbb')) #['abb'] print(re.findall('ab{2,4}','abbb')) #['abb'] print(re.findall('ab{1,}','abbb')) #'ab{1,}' ===> 'ab+' print(re.findall('ab{0,}','abbb')) #'ab{0,}' ===> 'ab*'
import re print(re.findall('a[1*-]b','a1b a*b a-b')) #[]内的都为普通字符 print(re.findall('a[^1*-]b','a1b a*b a-b a=b')) #[]内的^代表的意思是取反,所以结果为['a=b'] print(re.findall('a[0-9]b','a1b a*b a-b a=b')) print(re.findall('a[a-z]b','a1b a*b a-b a=b aeb')) print(re.findall('a[a-zA-Z]b','a1b a*b a-b a=b aeb aEb')) 运行结果: ['a1b', 'a*b', 'a-b'] ['a=b'] ['a1b'] ['aeb'] ['aeb', 'aEb']
#\# print(re.findall('a\\c','a\c')) #对于正则来说a\\c确实可以匹配到a\c,但是在python解释器读取a\\c时,会发生转义,然后交给re去执行,所以抛出异常 print(re.findall(r'a\\c','a\c')) #r代表告诉解释器使用rawstring,即原生字符串,把我们正则内的所有符号都当普通字符处理,不要转义 print(re.findall('a\\\\c','a\c')) #同上面的意思一样,和上面的结果一样都是['a\\c']
import re print(re.findall('ab+','ababab123')) #['ab', 'ab', 'ab'] print(re.findall('(ab)+123','ababab123')) #['ab'],匹配到末尾的ab123中的ab print(re.findall('(?:ab)+123','ababab123')) #findall的结果不是匹配的全部内容,而是组内的内容,?:可以让结果为匹配的全部内容 运行结果: ['ab', 'ab', 'ab'] ['ab'] ['ababab123']
import re print(re.findall('compan(?:y|ies)','Too many companies have gone bankrupt, and the next one is my company')) 运行结果: ['companies', 'company']
3)re模块提供方法:
import re print(re.findall('e','elaine make cake')) print(re.search('e','elaine make cake')) #e,只到找到第一个匹配然后返回一个包含匹配信息的对象,该对象可以通过调用group()方法得到匹配的字符串,如果字符串没有匹配,则返回None。 print(re.search('e','elaine make cake').group()) print(re.match('e','dylan elaine make cake')) # 在字符串开始匹配e,没有返回None print(re.search('^e','dylan elaine make cake')) # 和match效果一样 运行结果: ['e', 'e', 'e', 'e'] <_sre.SRE_Match object; span=(0, 1), match='e'> e None None
import re print(re.split('[bd]','abcdef')) # 先按b分割得到'a'和'cdef',再按d分割得到'c'和'ef' print(re.sub('e','E','elaine make cake')) # 不指定n,默认替换所有 print(re.sub('e','E','elaine make cake',1)) print(re.sub('e','E','elaine make cake',2)) print(re.sub('^(\w+)(.*?\s)(\w+)(.*?\s)(\w+)(.*?)$',r'\5\2\3\4\1','elaine make cake')) # 将elaine和cake替换位置 print(re.subn('e','E','elaine make cake')) # 结果带有总共替换的个数 运行结果: ['a', 'c', 'ef'] ElainE makE cakE Elaine make cake ElainE make cake cake make elaine ('ElainE makE cakE', 4)
4)补充:
在线调试工具:tool.oschina.net/regex/#
import re s = '1-12*(60+(-40.35/5.3+1.2)-(-4*3))' print(re.findall('\-?\d+\.?\d*',s)) # 找到所有数 print(re.findall('\-?\d+\.+\d+',s)) # 找到所有小数 print(re.findall('\-?\d+\.+\d+|(\-?\d+)',s)) # 找到所有整数 运行结果: ['1', '-12', '60', '-40.35', '5.3', '1.2', '-4', '3'] ['-40.35', '5.3', '1.2'] ['1', '-12', '60', '-40', '35', '5', '3', '1', '2', '-4', '3']
2.time模块:
在Python中,通常有这几种方式来表示时间:
- 时间戳(timestamp):通常来说,时间戳表示的是从1970年1月1日00:00:00开始按秒计算的偏移量。我们运行“type(time.time())”,返回的是float类型。
- 格式化的时间字符串(Format String)
- 结构化的时间(struct_time):struct_time元组共有9个元素共九个元素:(年,月,日,时,分,秒,一年中第几周,一年中第几天,夏令时)
import time #--------------------------三种形式的时间 print(time.time()) print(time.strftime("%Y-%m-%d %X")) print(time.localtime()) #本地时区的struct_time print(time.gmtime()) #UTC时区的struct_time # 运行结果: 1496641468.292337 2017-06-05 13:44:28 time.struct_time(tm_year=2017, tm_mon=6, tm_mday=5, tm_hour=13, tm_min=44, tm_sec=28, tm_wday=0, tm_yday=156, tm_isdst=0) time.struct_time(tm_year=2017, tm_mon=6, tm_mday=5, tm_hour=5, tm_min=44, tm_sec=28, tm_wday=0, tm_yday=156, tm_isdst=0)
其中计算机认识的时间只能是'时间戳'格式,而程序员可处理的或者说人类能看懂的时间有: '格式化的时间字符串','结构化的时间' ,于是有了下图的转换关系:

# localtime([secs]) # 将一个时间戳转换为当前时区的struct_time。secs参数未提供,则以当前时间为准。 print(time.localtime(time.time())) # gmtime([secs]) 和localtime()方法类似,gmtime()方法是将一个时间戳转换为UTC时区(0时区)的struct_time。 # mktime(t) : 将一个struct_time转化为时间戳。 print(time.mktime(time.localtime())) 运行结果: time.struct_time(tm_year=2017, tm_mon=6, tm_mday=5, tm_hour=13, tm_min=53, tm_sec=39, tm_wday=0, tm_yday=156, tm_isdst=0) 1496642019.0
''' strftime(format[, t]) : 把一个代表时间的元组或者struct_time(如由time.localtime()和 time.gmtime()返回)转化为格式化的时间字符串。如果t未指定,将传入time.localtime()。如果元组中任何一个 元素越界,ValueError的错误将会被抛出。 ''' print(time.strftime("%Y-%m-%d %X", time.localtime())) #"%Y-%m-%d %X"为固定格式,中间的-可以任意指定 # time.strptime(string[, format]): # 把一个格式化时间字符串转化为struct_time。实际上它和strftime()是逆操作 print(time.strptime("2017-06-05 13:59:31","%Y-%m-%d %X")) #在这个函数中,format默认为:"%a %b %d %H:%M:%S %Y"。 运行结果: 2017-06-05 14:02:15 time.struct_time(tm_year=2017, tm_mon=6, tm_mday=5, tm_hour=13, tm_min=59, tm_sec=31, tm_wday=0, tm_yday=156, tm_isdst=-1)

#--------------------------按图2转换时间 # asctime([t]) : 把一个表示时间的元组或者struct_time表示为这种形式:'Sun Jun 20 23:21:05 1993'。 # 如果没有参数,将会将time.localtime()作为参数传入。 print(time.asctime())#Sun Sep 11 00:43:43 2016 # ctime([secs]) : 把一个时间戳(按秒计算的浮点数)转化为time.asctime()的形式。如果参数未给或者为 # None的时候,将会默认time.time()为参数。它的作用相当于time.asctime(time.localtime(secs))。 print(time.ctime()) # Sun Sep 11 00:46:38 2016 print(time.ctime(time.time())) # Sun Sep 11 00:46:38 2016
#--------------------------其他用法 # sleep(secs) # 线程推迟指定的时间运行,单位为秒。
3.random模块:
import random print(random.random())#(0,1)----float 大于0且小于1之间的小数 print(random.randint(1,3)) #[1,3] 大于等于1且小于等于3之间的整数 print(random.randrange(1,3)) #[1,3) 大于等于1且小于3之间的整数 print(random.choice([1,'23',[4,5]]))#1或者23或者[4,5] print(random.sample([1,'23',[4,5]],2))#列表元素任意2个组合 print(random.uniform(1,3))#大于1小于3的小数,如1.927109612082716 item=[1,3,5,7,9] random.shuffle(item) #打乱item的顺序,相当于"洗牌" print(item)
应用:
生成随机验证码:
import random def auth_code(n): code = '' for i in range(n): num = random.randint(0,9) alf = chr(random.randint(65,90)) add = random.choice([num,alf]) code += str(add) return code print(auth_code(7))
4.os模块:
os.getcwd() 获取当前工作目录,即当前python脚本工作的目录路径 os.chdir("dirname") 改变当前脚本工作目录;相当于shell下cd os.curdir 返回当前目录: ('.') os.pardir 获取当前目录的父目录字符串名:('..') os.makedirs('dirname1/dirname2') 可生成多层递归目录 os.removedirs('dirname1') 若目录为空,则删除,并递归到上一级目录,如若也为空,则删除,依此类推 os.mkdir('dirname') 生成单级目录;相当于shell中mkdir dirname os.rmdir('dirname') 删除单级空目录,若目录不为空则无法删除,报错;相当于shell中rmdir dirname os.listdir('dirname') 列出指定目录下的所有文件和子目录,包括隐藏文件,并以列表方式打印 os.remove() 删除一个文件 os.rename("oldname","newname") 重命名文件/目录 os.stat('path/filename') 获取文件/目录信息 os.sep 输出操作系统特定的路径分隔符,win下为"\\",Linux下为"/" os.linesep 输出当前平台使用的行终止符,win下为"\t\n",Linux下为"\n" os.pathsep 输出用于分割文件路径的字符串 win下为;,Linux下为: os.name 输出字符串指示当前使用平台。win->'nt'; Linux->'posix' os.system("bash command") 运行shell命令,直接显示 os.environ 获取系统环境变量
import os # os.path.abspath(path) 返回path规范化的绝对路径 print(os.path.abspath('D:\python\python3')) # os.path.split(path) 将path分割成目录和文件名二元组返回 print(os.path.split('D:\python\python3')) # os.path.dirname(path) 返回path的目录。其实就是os.path.split(path)的第一个元素 print(os.path.dirname('D:\python\python3')) # os.path.basename(path) 返回path最后的文件名。如何path以/或\结尾,那么就会返回空值。即os.path.split(path)的第二个元素 print(os.path.basename('D:\python\python3')) # os.path.exists(path) 如果path存在,返回True;如果path不存在,返回False print(os.path.exists('D:\python\python3')) # os.path.isabs(path) 如果path是绝对路径,返回True print(os.path.isabs('D:\python\python3')) # os.path.isfile(path) 如果path是一个存在的文件,返回True。否则返回False print(os.path.isfile('D:\python\python3')) # os.path.isdir(path) 如果path是一个存在的目录,则返回True。否则返回False print(os.path.isdir('D:\python\python3')) # os.path.join(path1[, path2[, ...]]) 将多个路径组合后返回,第一个绝对路径之前的参数将被忽略 print(os.path.join('D:\python\python3','test.py')) print(os.path.join('test.py','D:\python\python3','test')) # os.path.getatime(path) 返回path所指向的文件或者目录的最后存取时间 print(os.path.getatime('D:\python\python3')) # os.path.getmtime(path) 返回path所指向的文件或者目录的最后修改时间 print(os.path.getmtime('D:\python\python3')) # os.path.getsize(path) 返回path的大小 print(os.path.getsize('D:\python\python3')) 运行结果: D:\python\python3 ('D:\\python', 'python3') D:\python python3 True True False True D:\python\python3\test.py D:\python\python3\test 1496627936.308156 1496627936.308156 4096
# 在Linux和Mac平台上,该函数会原样返回path,在windows平台上会将路径中所有字符转换为小写,并将所有斜杠转换为饭斜杠。 print(os.path.normcase('c:/windows\\system32\\')) # os.path.normpath 规范化路径,如..和/ print(os.path.normpath('c://windows\\System32\\../Temp/')) 运行结果: c:\windows\system32\ c:\windows\Temp
根据os.pardir和用来规范路径的os.path.normpath可以用来将开发的软件包的根目录导入环境变量sys.path,进而可以任意导入软件包里的模块:
# start_test.py import sys import os dir = os.path.normpath(os.path.join(os.path.abspath(__file__), # 当前文件的绝对路径 os.pardir, # 上一级目录 os.pardir,)) sys.path.insert(0,dir) print(sys.path) 运行结果: ['D:\\python\\python3', 'D:\\python\\python3\\s17day06_code', 'D:\\python\\python3', 'D:\\python\\python\\monitor_test', 'C:\\Windows\\system32\\python34.zip', 'C:\\Python34\\DLLs', 'C:\\Python34\\lib', 'C:\\Python34', 'C:\\Python34\\lib\\site-packages', 'C:\\Python34\\lib\\site-packages\\win32', 'C:\\Python34\\lib\\site-packages\\win32\\lib', 'C:\\Python34\\lib\\site-packages\\Pythonwin']
5.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 返回操作系统平台名称
模拟进度条:
import sys,time for i in range(50): sys.stdout.write('%s\r' %('#'*i)) # \r 为不换行,跳到行首 sys.stdout.flush() time.sleep(0.1) ''' 注意:在pycharm中执行无效,请到命令行中以脚本的方式执行 '''
6.shutil模块:
高级的 文件、文件夹、压缩包 处理模块
shutil.copyfileobj(fsrc, fdst[, length])
将文件内容拷贝到另一个文件中
import shutil shutil.copyfileobj(open('old.xml','r'), open('new.xml', 'w'))
shutil.copyfile(src, dst)
拷贝文件
shutil.copyfile('f1.log', 'f2.log') #目标文件无需存在
shutil.copymode(src, dst)
仅拷贝权限。内容、组、用户均不变
shutil.copymode('f1.log', 'f2.log') #目标文件必须存在
shutil.copystat(src, dst)
仅拷贝状态的信息,包括:mode bits, atime, mtime, flags
shutil.copystat('f1.log', 'f2.log') #目标文件必须存在
shutil.copy(src, dst)
拷贝文件和权限
import shutil shutil.copy('f1.log', 'f2.log')
shutil.copy2(src, dst)
拷贝文件和状态信息
import shutil shutil.copy2('f1.log', 'f2.log')
shutil.copytree(src, dst, symlinks=False, ignore=None)
递归的去拷贝文件夹
import shutil shutil.copytree('folder1', 'folder2', ignore=shutil.ignore_patterns('*.pyc', 'tmp*')) #目标目录不能存在,注意对folder2目录父级目录要有可写权限,ignore的意思是排除
import shutil shutil.copytree('f1', 'f2', symlinks=True, ignore=shutil.ignore_patterns('*.pyc', 'tmp*')) ''' 通常的拷贝都把软连接拷贝成硬链接,即对待软连接来说,创建新的文件 '''
shutil.rmtree(path[, ignore_errors[, onerror]])
递归的去删除文件
import shutil shutil.rmtree('folder1')
shutil.move(src, dst)
递归的去移动文件,它类似mv命令,其实就是重命名
import shutil shutil.move('folder1', 'folder3')
shutil.make_archive(base_name, format,...)
- base_name: 压缩包的文件名,也可以是压缩包的路径。只是文件名时,则保存至当前目录,否则保存至指定路径:
如: data_bak =>保存至当前路径
如:/tmp/data_bak =>保存至/tmp/
- format: 压缩包种类,“zip”, “tar”, “bztar”,“gztar”
- root_dir: 要压缩的文件夹路径(默认当前目录)
- owner: 用户,默认当前用户
- group: 组,默认当前组
- logger: 用于记录日志,通常是logging.Logger对象
#将 /data 下的文件打包放置当前程序目录 import shutil ret = shutil.make_archive("data_bak", 'gztar', root_dir='/data') #将 /data下的文件打包放置 /tmp/目录 import shutil ret = shutil.make_archive("/tmp/data_bak", 'gztar', root_dir='/data')
shutil 对压缩包的处理是调用 ZipFile 和 TarFile 两个模块来进行的:
import zipfile # 压缩 z = zipfile.ZipFile('laxi.zip', 'w') z.write('a.log') z.write('data.data') z.close() # 解压 z = zipfile.ZipFile('laxi.zip', 'r') z.extractall(path='.') z.close() zipfile压缩解压缩
import tarfile # 压缩 >>> t=tarfile.open('/tmp/egon.tar','w') >>> t.add('/test1/a.py',arcname='a.bak') >>> t.add('/test1/b.py',arcname='b.bak') >>> t.close() # 解压 >>> t=tarfile.open('/tmp/egon.tar','r') >>> t.extractall('/egon') >>> t.close() tarfile压缩解压缩
7.json,pickle模块:
之前我们学习过用eval内置方法可以将一个字符串转成python对象,不过,eval方法是有局限性的,对于普通的数据类型,json.loads和eval都能用,但遇到特殊类型的时候,eval就不管用了,所以eval的重点还是通常用来执行一个字符串表达式,并返回表达式的值。
import json x="[null,true,false,1]" # print(eval(x)) #报错,无法解析null类型,而json就可以 print(json.loads(x)) 运行结果: [None, True, False, 1]
为什么要序列化?
1)持久保存状态:
需知一个软件/程序的执行就在处理一系列状态的变化,在编程语言中,'状态'会以各种各样有结构的数据类型(也可简单的理解为变量)的形式被保存在内存中。
内存是无法永久保存数据的,当程序运行了一段时间,我们断电或者重启程序,内存中关于这个程序的之前一段时间的数据(有结构)都被清空了。
在断电或重启程序之前将程序当前内存中所有的数据都保存下来(保存到文件中),以便于下次程序执行能够从文件中载入之前的数据,然后继续执行,这就是序列化。
具体的来说,你玩使命召唤闯到了第13关,你保存游戏状态,关机走人,下次再玩,还能从上次的位置开始继续闯关。或如,虚拟机状态的挂起等。
2)跨平台数据交互:
序列化之后,不仅可以把序列化后的内容写入磁盘,还可以通过网络传输到别的机器上,如果收发的双方约定好实用一种序列化的格式,那么便打破了平台/语言差异化带来的限制,实现了跨平台数据交互。
反过来,把变量内容从序列化的对象重新读到内存里称之为反序列化,即unpickling。
json:
如果我们要在不同的编程语言之间传递对象,就必须把对象序列化为标准格式,比如XML,但更好的方法是序列化为JSON,因为JSON表示出来就是一个字符串,可以被所有语言读取,也可以方便地存储到磁盘或者通过网络传输。JSON不仅是标准格式,并且比XML更快,而且可以直接在Web页面中读取,非常方便。
JSON表示的对象就是标准的JavaScript语言的对象,JSON和Python内置的数据类型对应如下:


对一段python数据类型我们可以使用json方式对其进行序列化和反序列化:
# 序列化 import json dic = { 'name':'elaine', 'age':18, 'gender':'girl' } res = json.dumps(dic) with open('a.json','w') as f : f.write(res) #反序列化: with open('a.json','r') as f : data = f.read() res = json.loads(data) print(res,type(res)) # 运行结果: {'gender': 'girl', 'age': 18, 'name': 'elaine'} <class 'dict'> # 也可以用简便方式: # 序列化: dic = { 'name':'elaine', 'age':18, 'gender':'girl' } json.dump(dic,open('b.json','w')) # 反序列化: res = json.load(open('b.json','r')) print(res,type(res)) #运行结果: {'name': 'elaine', 'age': 18, 'gender': 'girl'} <class 'dict'>
pickle:
同样,对一段python数据类型我们也可以使用pickle方式对其进行序列化和反序列化:
# 序列化: import pickle dic = { 'name':'elaine', 'age':18, 'gender':'girl' } pickle.dump(dic,open('a.plk','wb')) #使用二进制方式打开 #反序列化: res = pickle.load(open('a.plk','rb')) print(res,type(res)) 运行结果: {'name': 'elaine', 'gender': 'girl', 'age': 18} <class 'dict'>
函数作为python的对象,是否可以被pickle序列化呢?
import pickle def func(): print('from func') pickle.dump(func,open('func.plk','wb'))
序列化没问题,我们进行反序列化:
import pickle pickle.load(open('func.plk','rb')) 运行结果: Traceback (most recent call last): File "D:/python/python3/s17day06_code/pickle模块.py", line 25, in <module> pickle.load(open('func.plk','rb')) AttributeError: Can't get attribute 'func' on <module '__main__' from 'D:/python/python3/s17day06_code/pickle模块.py'>
对于函数来说,pickle序列化的只是其内存地址(函数名),而没有这个内存地址对应的值,而对于普通的数据类型(字典,列表,元组)序列化的是其值的本身,反序列化会在内存中重新定义这个数据类型。
8.shelve模块:
shelve模块比pickle模块简单,只有一个open函数,返回类似字典的对象,可读可写;key必须为字符串,而值可以是python所支持的数据类型
import shelve with shelve.open('test') as s: s['user_info1'] = {'name':'elaine','age':18} s['user_info2'] = {'name': 'dylan', 'age': 29} print(s['user_info1']['name']) 运行结果: elaine
9.xml模块:
xml是实现不同语言或程序之间进行数据交换的协议,跟json差不多,但json使用起来更简单,至今很多传统公司如金融行业的很多系统的接口还主要是xml。
<?xml version="1.0"?> <data> <country name="Liechtenstein"> <rank updated="yes">2</rank> <year>2008</year> <gdppc>141100</gdppc> <neighbor name="Austria" direction="E"/> <neighbor name="Switzerland" direction="W"/> </country> <country name="Singapore"> <rank updated="yes">5</rank> <year>2011</year> <gdppc>59900</gdppc> <neighbor name="Malaysia" direction="N"/> </country> <country name="Panama"> <rank updated="yes">69</rank> <year>2011</year> <gdppc>13600</gdppc> <neighbor name="Costa Rica" direction="W"/> <neighbor name="Colombia" direction="E"/> </country> </data> xml数据
import xml.etree.ElementTree as ET tree = ET.parse('xml_test') # 导入xml文件 root = tree.getroot() # 生成根节点 print(root.tag) # 根节点标签名 print(root.iter('year')) #全文搜索 print(root.find('country')) #只在root的子节点找,只找一个 print(root.findall('country')) #只在root的子节点找,找所有 for i in root: # 遍历xml文档,得到root下子节点对象 print(i.tag,':%s'%i.attrib['name']) for n in i : print('====> tag:%s attrib:%s text:%s'%(n.tag,n.attrib,n.text)) for i in root.iter('year'): # 遍历找到的year节点 print('tag:%s text:%s'%(i.tag,i.text)) 运行结果: data # 根节点的tag <_elementtree._element_iterator object at 0x0000000000828EA0> # 搜索到所有year节点的对象 <Element 'country' at 0x0000000000C2CD68> # 根下第一个找到的country节点对象 [<Element 'country' at 0x0000000000C2CD68>, <Element 'country' at 0x0000000000C40778>, <Element 'country' at 0x0000000000C40908>] # 根节点下找到的所有的country节点对象 country :Liechtenstein ====> tag:rank attrib:{'updated': 'yes'} text:2 ====> tag:year attrib:{} text:2008 ====> tag:gdppc attrib:{} text:141100 ====> tag:neighbor attrib:{'name': 'Austria', 'direction': 'E'} text:None ====> tag:neighbor attrib:{'name': 'Switzerland', 'direction': 'W'} text:None country :Singapore ====> tag:rank attrib:{'updated': 'yes'} text:5 ====> tag:year attrib:{} text:2011 ====> tag:gdppc attrib:{} text:59900 ====> tag:neighbor attrib:{'name': 'Malaysia', 'direction': 'N'} text:None country :Panama ====> tag:rank attrib:{'updated': 'yes'} text:69 ====> tag:year attrib:{} text:2011 ====> tag:gdppc attrib:{} text:13600 ====> tag:neighbor attrib:{'name': 'Costa Rica', 'direction': 'W'} text:None ====> tag:neighbor attrib:{'name': 'Colombia', 'direction': 'E'} text:None tag:year text:2008 tag:year text:2011 tag:year text:2011
# 修改所有year节点 for node in root.iter('year'): new_year = int(node.text) + 1 node.text = str(new_year) node.set('updated', 'yes') # 设置updated属性 node.set('version', '1.0') # 设置version属性 tree.write('test.xml') # 写入test.xml
import xml.etree.ElementTree as ET tree = ET.parse('xml_test') # 导入xml文件 root = tree.getroot() # 生成根节点 # 删除year.text大于2010的year节点 for country_node in root: year_node = country_node.find('year') if int(year_node.text) > 2010: country_node.remove(year_node) # 因为year节点在country下,所以必须从country节点下删除 tree.write('test02.xml')
# 在country添加year2节点 import xml.etree.ElementTree as ET tree = ET.parse("a.xml") root=tree.getroot() for country_node in root : for year_node in country_node.findall('year'): if int(year_node.text) > 2000: year2 = ET.Element('year2') year2.text = '千禧年' year2.attrib = {'update':'yes'} #或者year2.set('update','yes') country_node.append(year2) #往country节点下添加子节点 tree.write('test03.xml')
#创建自定义xml import xml.etree.ElementTree as ET new_xml = ET.Element("namelist") name = ET.SubElement(new_xml,"name",attrib={"enrolled":"yes"}) age = ET.SubElement(name,"age",attrib={"checked":"no"}) sex = ET.SubElement(name,"sex") sex.text = '33' name2 = ET.SubElement(new_xml,"name",attrib={"enrolled":"no"}) age = ET.SubElement(name2,"age") age.text = '19' et = ET.ElementTree(new_xml) #生成文档对象 et.write("test.xml", encoding="utf-8",xml_declaration=True) ET.dump(new_xml) #打印生成的格式
10.hashlib模块:
hash:一种算法 ,3.x里代替了md5模块和sha模块,主要提供 SHA1, SHA224, SHA256, SHA384, SHA512,MD5 算法
三个特点:
1.内容相同则hash运算结果相同,内容稍微改变则hash值则变
2.不可逆推
3.相同算法:无论校验多长的数据,得到的哈希值长度固定。
import hashlib m = hashlib.md5() m.update('hello'.encode('utf-8')) print(m.hexdigest()) # 5d41402abc4b2a76b9719d911017c592 m.update('elaine'.encode('utf-8')) print(m.hexdigest()) # b24d57a2292ed7bec0c15e3c7ebe6f29 m2 = hashlib.md5() m2.update('helloelaine'.encode('utf-8')) print(m2.hexdigest()) # b24d57a2292ed7bec0c15e3c7ebe6f29 ''' 把一段很长的数据update多次,与一次update这段长数据,得到的结果一样 ,update多次为校验大文件提供了可能。 '''
m = hashlib.md5() with open(r'E:\war3\YDWE1.27.6正式版\backups\0.w3x','rb') as f: for line in f: m.update(line) md5_num = m.hexdigest() print(md5_num) m2 = hashlib.md5() with open(r'E:\war3\YDWE1.27.6正式版\backups\0.w3x','rb') as f: data = f.read() m2.update(data) md5_num = m2.hexdigest() print(md5_num) 运行结果: a976202f4ad8e6fa9bb9992fe71cc7c7 a976202f4ad8e6fa9bb9992fe71cc7c7
以上加密算法虽然依然非常厉害,但时候存在缺陷,即:通过撞库可以反解。所以,有必要对加密算法中添加自定义key再来做加密。
import hashlib # ######## 256 ######## hash = hashlib.sha256('898oaFs09f'.encode('utf8')) hash.update('alvin'.encode('utf8')) print (hash.hexdigest())#e79e68f070cdedcfe63eaf1a2e92c83b4cfb1b5c6bc452d214c1b7e77cdfd1c7
import hashlib passwds=[ 'elaine123', 'elaine456', 'elaine789', 'elaine234', 'elaine345', 'elaine6789', ] def make_passwd_dic(passwds): dic={} for passwd in passwds: m=hashlib.md5() m.update(passwd.encode('utf-8')) dic[passwd]=m.hexdigest() return dic def break_code(cryptograph,passwd_dic): for k,v in passwd_dic.items(): if v == cryptograph: print('密码是===>\033[46m%s\033[0m' %k) cryptograph='92dd15c5552dc0df831ed2eddcbea0c5' break_code(cryptograph,make_passwd_dic(passwds)) 运行结果: 密码是===>elaine789
11.subprocess模块:
os.system()模块可以直接执行命令将其打印到终端,但是往往我们想通过一种方式在服务端执行命令,需要通过另外的方式输出到其它终端上,我们可以通过subprocess实现:
import subprocess res = subprocess.Popen('dir',shell=True,stdout=subprocess.PIPE) # 使用stdout接收存储执行的命令正确的结果 # print(res.stdout.read()) # 输出为bytes格式,需要decode为当前系统的编码格式 print(res.stdout.read().decode('gbk'))
import subprocess res = subprocess.Popen('dir_test',shell=True,stderr=subprocess.PIPE,stdout=subprocess.PIPE) # 使用stderr来接收存储错误的命令结果 # print(res.stdout.read()) print(res.stdout.read().decode('gbk')) print(res.stderr.read().decode('gbk')) 运行结果: 'dir_test' 不是内部或外部命令,也不是可运行的程序 或批处理文件。
# 模拟一个windows下的dir | findstr test* 类似linux下的ls /root |grep txt$ import subprocess res1 = subprocess.Popen('dir D:\python\py17\code\py17day06',shell=True,stdout=subprocess.PIPE) # 将第一条命令的stdout 以stdin的方式传给第二条命令 res = subprocess.Popen("findstr test*",shell=True,stdin=res1.stdout,stdout=subprocess.PIPE) print(res.stdout.read().decode('gbk')) 运行结果: 2017/06/04 15:42 462 json_test.py 2017/06/04 16:03 282 pickle_test01.py 2017/06/04 13:31 522 test.py 2017/06/04 15:40 47 test01.json
12.logging模块:
用于便捷记录日志且线程安全的模块
注:
1)如果不指定filename,则默认打印到终端
2)指定日志级别:
指定方式:
1:level=10
2:level=logging.ERROR
日志级别种类:
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
3)指定日志级别为ERROR,则只有ERROR及其以上级别的日志会被打印
import logging logging.basicConfig(filename='test.log', # 将日志写入test.log format='%(asctime)s - %(name)s - %(levelname)s -%(module)s: %(message)s', # 指定日志格式 datefmt='%Y-%m-%d %H:%M:%S %p', # 指定日期时间格式 level=10 # 指定日志级别,如果level=40,只有logging.error和logging.critical会被打印 ) logging.debug('debug') logging.info('info') logging.warning('warning') logging.error('error') logging.critical('critical')
运行后写入test.log结果:
2017-06-06 10:50:28 AM - root - DEBUG -logging_test: debug
2017-06-06 10:50:28 AM - root - INFO -logging_test: info
2017-06-06 10:50:28 AM - root - WARNING -logging_test: warning
2017-06-06 10:50:28 AM - root - ERROR -logging_test: error
2017-06-06 10:50:28 AM - root - CRITICAL -logging_test: critical
可在logging.basicConfig()函数中通过具体参数来更改logging模块默认行为,可用参数有
filename:用指定的文件名创建FiledHandler(后边会具体讲解handler的概念),这样日志会被存储在指定的文件中。
filemode:文件打开方式,在指定了filename时使用这个参数,默认值为“a”还可指定为“w”。
format:指定handler使用的日志显示格式。
datefmt:指定日期时间格式。
level:设置rootlogger(后边会讲解具体概念)的日志级别
stream:用指定的stream创建StreamHandler。可以指定输出到sys.stderr,sys.stdout或者文件,默认为sys.stderr。若同时列出了filename和stream两个参数,则stream参数会被忽略。http://blog.csdn.net/zyz511919766/article/details/25136485/
日志格式:
|
%(name)s |
|
|
%(levelno)s |
数字形式的日志级别 |
|
%(levelname)s |
文本形式的日志级别 |
|
%(pathname)s |
调用日志输出函数的模块的完整路径名,可能没有 |
|
%(filename)s |
调用日志输出函数的模块的文件名 |
|
%(module)s |
调用日志输出函数的模块名 |
|
%(funcName)s |
调用日志输出函数的函数名 |
|
%(lineno)d |
调用日志输出函数的语句所在的代码行 |
|
%(created)f |
当前时间,用UNIX标准的表示时间的浮 点数表示 |
|
%(relativeCreated)d |
输出日志信息时的,自Logger创建以 来的毫秒数 |
|
%(asctime)s |
字符串形式的当前时间。默认格式是 “2003-07-08 16:49:45,896”。逗号后面的是毫秒 |
|
%(thread)d |
线程ID。可能没有 |
|
%(threadName)s |
线程名。可能没有 |
|
%(process)d |
进程ID。可能没有 |
|
%(message)s |
用户输出的消息 |
13.configparser模块:
[section1] k1 = v1 k2:v2 user=elaine age=18 is_admin=true salary=31 [section2] k1 = v1
基本用法:
读取:
import configparser config = configparser.ConfigParser() config.read('config_test') #查看所有的标题 sec = config.sections() print(sec) #查看标题section1下所有key=value的key opt = config.options('section1') print(opt) #查看标题section1下所有key=value的(key,value)格式 items = config.items('section1') print(items) #查看标题section1下user的值=>字符串格式 get_value = config.get('section1','user') print(get_value) #查看标题section1下age的值=>整数格式 val1=config.getint('section1','age') print(val1) #18 #查看标题section1下is_admin的值=>布尔值格式 val2=config.getboolean('section1','is_admin') print(val2) #True #查看标题section1下salary的值=>浮点型格式 val3=config.getfloat('section1','salary') print(val3) #31.0 运行结果: ['section1', 'section2'] ['k1', 'k2', 'user', 'age', 'is_admin', 'salary'] [('k1', 'v1'), ('k2', 'v2'), ('user', 'elaine'), ('age', '18'), ('is_admin', 'true'), ('salary', '31')] elaine 18 True 31.0
改写,删除,添加:
import configparser config = configparser.ConfigParser() config.read('config_test') # 设置sections1下的user为dylan val = config.set('section1','user','dylan') #删除整个标题section2 config.remove_section('section2') #删除标题section1下的某个k1和k2 config.remove_option('section1','k1') config.remove_option('section1','k2') #判断是否存在某个标题 print(config.has_section('section1')) #判断标题section1下是否有user print(config.has_option('section1','user')) #添加一个标题 config.add_section('section3') #在标题section3下添加user=dylan,age=29的配置 config.set('section3','user','dylan') config.set('section3','age',29) # 报错,必须是字符串 #最后将修改的内容写入文件,完成最终的修改 config.write(open('a.cfg','w'))
二、软件开发规范

浙公网安备 33010602011771号