Python自动化开发—Day8
1、模块调用:
定义:其实模块简单说就是一堆代码实现某个功能,它们是已经写好的.py文件。只需要用import应用即可。
分类:
1、自定义模块
2、内置标准模块(又称标准库)
3、开源模块
1、自定义模块,就是自己写的.py文件为了实现某个功能。
2、内置模块,就是python自身已经写好的某个功能,例如经常用的sys、os等模块都是内置模块。
3、开源模块,开源大家都明白吧,就是不收费的别人写好的模块,一般也称第三方模块。
模块的引用:
1、import modules
2、from modules import 函数
3、如果有多个模块,可以用逗号隔开,如果想把某个模块里面的所有功能都导入,可以用*,这样的话功能都加载道内存里面,占用内存资源,不建议用
2、time &datetime模块:
Python的time模块实现主要调用C库,所以各个平台可能有所不同。time模块表示时间的有三种类型:
(1)timestamp 时间戳,时间戳表示的是从1970年1月1日00:00:00开始按秒计算的偏移量。返回时间戳方式的函数主要有time(),clock()等;
(2)struct_time 时间元组,共有九个元素。返回struct_time的函数主要有gmtime(),localtime(),strptime();
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
'''在Python中,通常有这几种方式来表示时间: 时间戳(timestamp):通常来说,时间戳表示的是从1970年1月1日00:00:00开始按秒计算的偏移量。 我们运行“type(time.time())”,返回的是float类型。 格式化的时间字符串(Format String) 结构化的时间(struct_time):struct_time元组共有9个元素共九个元素: (年,月,日,时,分,秒,一年中第几周,一年中第几天,夏令时)''' import time # print(time.time())#1535340758.6987474 # print(time.strftime("%Y-%m-%d %X")) #格式化的时间字符串:'2017-02-15 11:40:53' # print(time.localtime()) #本地时区的struct_time # print(time.gmtime()) #UTC时区的struct_time,相差8小时 '''其中计算机认识的时间只能是'时间戳'格式, 而程序员可处理的或者说人类能看懂的时间有: '格式化的时间字符串','结构化的时间' ,于是有了下图的转换关系''' '''timestamp--->struct_time:localtime、gmtime struct_time-->timestamp: mktime''' print(time.time()) # gmtime([secs]) 和localtime()方法类似,gmtime()方法是将一个时间戳转换为UTC时区(0时区)的struct_time。 print(time.localtime())#不传参数转换本地时间 print(time.localtime(3443434))#转换成相对应的时间 print(time.gmtime()) print(time.mktime(time.localtime(3443434))) ''' struct_time-->Format String: strftime Format String-->struct_time:strptime ''' print(time.strftime("%Y-%m-%d %X",time.localtime())) print(time.strptime('2018-08-27 16:37:06', '%Y-%m-%d %X')) ''' #--------------------------按图2转换时间 # asctime([t]) : 把一个表示时间的元组或者struct_time表示为这种形式:'Sun Jun 20 23:21:05 1993'。 # 如果没有参数,将会将time.localtime()作为参数传入。''' print(time.asctime())#Mon Aug 27 13:53:43 2018 '''# ctime([secs]) : 把一个时间戳(按秒计算的浮点数)转化为time.asctime()的形式。如果参数未给或者为 # None的时候,将会默认time.time()为参数。它的作用相当于time.asctime(time.localtime(secs))。''' print(time.ctime()) # Mon Aug 27 13:53:43 2018 print(time.ctime(time.time())) # Mon Aug 27 13:53:43 2018
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#时间加减 import datetime # print(datetime.datetime.now()) #返回 2016-08-19 12:47:03.941925 #print(datetime.date.fromtimestamp(time.time()) ) # 时间戳直接转成日期格式 2016-08-19 # print(datetime.datetime.now() ) # print(datetime.datetime.now() + datetime.timedelta(3)) #当前时间+3天 # print(datetime.datetime.now() + datetime.timedelta(-3)) #当前时间-3天 # print(datetime.datetime.now() + datetime.timedelta(hours=3)) #当前时间+3小时 # print(datetime.datetime.now() + datetime.timedelta(minutes=30)) #当前时间+30分 # # c_time = datetime.datetime.now() # print(c_time.replace(minute=3,hour=2)) #时间替换 datetime模块
3、random模块:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
import random def make_code(n): res='' for i in range(n): s1=chr(random.randint(65,90)) s2=str(random.randint(0,9)) res+=random.choice([s1,s2]) return res print(make_code(4))
4、OS模块
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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 获取系统环境变量 os.path.abspath(path) 返回path规范化的绝对路径 os.path.split(path) 将path分割成目录和文件名二元组返回 os.path.dirname(path) 返回path的目录。其实就是os.path.split(path)的第一个元素 os.path.basename(path) 返回path最后的文件名。如何path以/或\结尾,那么就会返回空值。即os.path.split(path)的第二个元素 os.path.exists(path) 如果path存在,返回True;如果path不存在,返回False os.path.isabs(path) 如果path是绝对路径,返回True os.path.isfile(path) 如果path是一个存在的文件,返回True。否则返回False os.path.isdir(path) 如果path是一个存在的目录,则返回True。否则返回False os.path.join(path1[, path2[, ...]]) 将多个路径组合后返回,第一个绝对路径之前的参数将被忽略 os.path.getatime(path) 返回path所指向的文件或者目录的最后存取时间 os.path.getmtime(path) 返回path所指向的文件或者目录的最后修改时间 os.path.getsize(path) 返回path的大小
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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__))))
5、sys模块
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#=========实现打印进度条函数========== import sys import time def progress(percent,width=50): if percent >= 1: percent=1 show_str=('[%%-%ds]' %width) %(int(width*percent)*'#') print('\r%s %d%%' %(show_str,int(100*percent)),file=sys.stdout,flush=True,end='') #=========应用========== data_size=1025 recv_size=0 while recv_size < data_size: time.sleep(0.1) #模拟数据的传输延迟 recv_size+=1024 #每次收1024 percent=recv_size/data_size #接收的比例 progress(percent,width=70) #进度条的宽度70
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
''' # 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 print(sys.argv) print(sys.version) print(sys.path) print(sys.platform)
6、hashlib模块
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
# 1、什么叫hash:hash是一种算法(3.x里代替了md5模块和sha模块,主要提供 SHA1, SHA224, SHA256, SHA384, SHA512 ,MD5 算法),该算法接受传入的内容,经过运算得到一串hash值 # 2、hash值的特点是: #2.1 只要传入的内容一样,得到的hash值必然一样=====>要用明文传输密码文件完整性校验 #2.2 不能由hash值返解成内容=======》把密码做成hash值,不应该在网络传输明文密码 #2.3 只要使用的hash算法不变,无论校验的内容有多大,得到的hash值长度是固定的 import hashlib m=hashlib.md5()# m=hashlib.sha256() m.update('hello'.encode('utf8')) print(m.hexdigest()) #5d41402abc4b2a76b9719d911017c592 m.update('alvin'.encode('utf8')) print(m.hexdigest()) #92a7e713c30abbb0319fa07da2a5c4af m2=hashlib.md5() m2.update('helloalvin'.encode('utf8')) print(m2.hexdigest()) #92a7e713c30abbb0319fa07da2a5c4af ''' 注意:把一段很长的数据update多次,与一次update这段长数据,得到的结果一样 但是update多次为校验大文件提供了可能。 '''
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#python 还有一个 hmac 模块,它内部对我们创建 key 和 内容 进行进一步的处理然后再加密 #要想保证hmac最终结果一致,必须保证: #1:hmac.new括号内指定的初始key一样 #2:无论update多少次,校验的内容累加到一起是一样的内容 import hmac h1=hmac.new(b'egon') h1.update(b'hello') h1.update(b'world') print(h1.hexdigest()) h2=hmac.new(b'egon') h2.update(b'helloworld') print(h2.hexdigest()) h3=hmac.new(b'egonhelloworld') print(h3.hexdigest()) ''' f1bf38d054691688f89dcd34ac3c27f2 f1bf38d054691688f89dcd34ac3c27f2 bcca84edd9eeb86f30539922b28f3981 ''' 注意!注意!注意
7、shutil模块
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#高级的 文件、文件夹、压缩包 处理模块 import shutil #shutil.copyfileobj(fsrc, fdst[, length])将文件内容拷贝到另一个文件中 # f = open('xiaoming.txt','w',encoding='utf-8') # f.write('小明你在哪里') # f.close() shutil.copyfileobj(open('xiaoming.txt','r',encoding='utf-8'),open('xiaoming02.txt','w',encoding='utf-8')) #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)拷贝文件和权限 shutil.copy('f1.log', 'f2.log') #shutil.copy2(src, dst)拷贝文件和状态信息 shutil.copy2('f1.log', 'f2.log') '''shutil.ignore_patterns(*patterns) shutil.copytree(src, dst, symlinks=False, ignore=None) 递归的去拷贝文件夹''' shutil.copytree('folder1', 'folder2', ignore=shutil.ignore_patterns('*.pyc', 'tmp*')) # 目标目录不能存在,注意对folder2目录父级目录要有可写权限,ignore的意思是排除 shutil.copytree('f1', 'f2', symlinks=True, ignore=shutil.ignore_patterns('*.pyc', 'tmp*')) ''' 通常的拷贝都把软连接拷贝成硬链接,即对待软连接来说,创建新的文件 ''' #shutil.rmtree(path[, ignore_errors[, onerror]])递归的去删除文件 shutil.rmtree('folder1') #shutil.move(src, dst)递归的去移动文件,它类似mv命令,其实就是重命名。 shutil.move('folder1', 'folder3')
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
'''shutil.make_archive(base_name, format,...) 创建压缩包并返回文件路径,例如:zip、tar base_name: 压缩包的文件名,也可以是压缩包的路径。只是文件名时,则保存至当前目录,否则保存至指定路径, 如:www =>保存至当前路径 如:/Users/wupeiqi/www =>保存至/Users/wupeiqi/ format:压缩包种类,“zip”, “tar”, “bztar”,“gztar” root_dir:要压缩的文件夹路径(默认当前目录) owner:用户,默认当前用户 group: 组,默认当前组 logger:用于记录日志,通常是logging.Logger对象''' import shutil shutil.make_archive('xiaomingejjj','zip')
8、shelve模块
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
''' shelve模块比pickle模块简单,只有一个open函数,返回类似字典的对象, 可读可写;key必须为字符串,而值可以是python所支持的数据类型 ''' import shelve f= shelve.open(r'sheve.txt') f['stu1_info']={'name':'egon','age':18,'hobby':['piao','smoking','drinking']} # f['stu2_info']={'name':'gangdan','age':53} # f['school_info']={'website':'http://www.pypy.org','city':'beijing'} print(f['stu1_info']['hobby'])#['piao', 'smoking', 'drinking'] f.close()
9、xml模块
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
''' xml的格式如下,就是通过<>节点来区别数据结构的: # print(root.iter('year')) #全文搜索 # print(root.find('country')) #在root的子节点找,只找一个 # print(root.findall('country')) #在root的子节点找,找所有 ''' #1、解析XML from xml.etree import cElementTree as ET tree = ET.parse("xmltest.xml") # 获取xml文件的根节点 root = tree.getroot() print(root) #遍历xml:查 attrib:标签属性 for child in root: print('========>', child.tag, child.attrib, child.attrib['name']) for i in child: print(i.tag, i.attrib, i.text) print('---------------------------------------') # 只遍历year 节点 for node in root.iter('year'): print(node.tag, node.text) print('---------------------------------------') #修改的节点,均是在内存中进行,其不会影响文件中的内容。所以,如果想要修改,则需要重新将内存中的内容写到文件。 for note in root.iter('year'): new_year = int(note.text)+1#更改属性 note.text = str(new_year) note.set('update','yes')#设置属性 note.set('version','1.0') tree.write('xmltest.xml') for node in root.iter('year'): print(node.tag, node.text) #删除 for country in root.findall('country'): rank =int(country.find('rank').text) if rank > 50: root.remove(country) tree.write('xmltest.xml')
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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、configparser模块
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
import configparser config=configparser.ConfigParser() config.read('a.cfg') #查看所有的标题 res=config.sections() #['section1', 'section2'] print(res) #查看标题section1下所有key=value的key options=config.options('section1') print(options) #['k1', 'k2', 'user', 'age', 'is_admin', 'salary'] #查看标题section1下所有key=value的(key,value)格式 item_list=config.items('section1') print(item_list) #[('k1', 'v1'), ('k2', 'v2'), ('user', 'egon'), ('age', '18'), ('is_admin', 'true'), ('salary', '31')] #查看标题section1下user的值=>字符串格式 val=config.get('section1','user') print(val) #egon #查看标题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 import configparser config=configparser.ConfigParser() config.read('a.cfg',encoding='utf-8') #删除整个标题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','')) #添加一个标题 config.add_section('egon') #在标题egon下添加name=egon,age=18的配置 config.set('egon','name','egon') config.set('egon','age',18) #报错,必须是字符串 #最后将修改的内容写入文件,完成最终的修改 config.write(open('a.cfg','w'))
11、re模块
re.match 从头开始匹配
re.search 匹配包含
re.findall 把所有匹配到的字符放到以列表中的元素返回
re.splitall 以匹配到的字符当做列表分隔符
re.sub 匹配字符并替换
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
import re ''' ^元字符:字符串开始位置与匹配规则符合就匹配,否则不匹配,匹配字符串开头。在多行模式中匹配每一行的开头 ^元字符如果写到[]字符集里就是反取 ''' print(re.findall('^h','hello world xiao123ming'))#['h'] print(re.findall('^e','hello world xiao123ming'))#[] print(re.findall('[^a-z]','hello world xiao123ming'))#[' ', ' ', '1', '2', '3'] ''' $元字符:字符串结束位置与匹配规则符合就匹配,否则不匹配,匹配字符串末尾,在多行模式中匹配每一行的末尾 ''' print(re.findall('g$','hello world xiao123ming'))#['g'] print(re.findall('a$','hello world xiao123ming'))#[] ''' *元字符:需要字符串里完全符合,匹配规则,就匹配,(规则里的*元字符)前面的一个字符可以是0个或多个原本字符 匹配前一个字符0或多次,贪婪匹配前导字符有多少个就匹配多少个很贪婪 如果规则里只有一个分组,尽量避免用*否则会有可能匹配出空字符串''' print(re.findall('oa*','hello world xiao123mingoa'))#['o', 'o', 'o', 'oa'] print(re.findall("匹配规则*", "这个字符串是否匹配规则则则则则"))#['匹配规则则则则则'] ''' +元字符:需要字符串里完全符合,匹配规则,就匹配,(规则里的+元字符)前面的一个字符可以是1个或多个原本字符 匹配前一个字符1次或无限次,贪婪匹配前导字符有多少个就匹配多少个很贪婪 ''' print(re.findall('oa+','hello world xiao123mingoa'))#['oa'] ''' ?元字符,和防止贪婪匹配:需要字符串里完全符合,匹配规则,就匹配,(规则里的?元字符)前面的一个字符可以是0个或1个原本字符 匹配一个字符0次或1次,还有一个功能是可以防止贪婪匹配,详情见防贪婪匹配 ''' print(re.findall('oa?','hello world xiao123mingoa'))#['o', 'o', 'o', 'oa'] ''' {}元字符,范围: 需要字符串里完全符合,匹配规则,就匹配,(规则里的 {} 元字符)前面的一个字符,是自定义字符数,位数的原本字符 {m}匹配前一个字符m次,{m,n}匹配前一个字符m至n次,若省略n,则匹配m至无限次 {0,}匹配前一个字符0或多次,等同于*元字符 {+,}匹配前一个字符1次或无限次,等同于+元字符 {0,1}匹配前一个字符0次或1次,等同于?元字符 ''' print(re.findall('oa{2}','hello world xiao123mingoaaaaa'))#['oaa'] ''' []元字符,字符集: 需要字符串里完全符合,匹配规则,就匹配,(规则里的 [] 元字符)对应位置是[]里的任意一个字符就匹配 字符集。对应的位置可以是字符集中任意字符。字符集中的字符可以逐个列出, 也可以给出范围,如[abc]或[a-c]。[^abc]表示取反,即非abc。 所有特殊字符在字符集中都失去其原有的特殊含义。用\反斜杠转义恢复特殊字符的特殊含义。 ''' print(re.findall("匹配[a,b,c]规则", "匹配a规则这个字符串是否匹配b规则则则则则"))#['匹配a规则', '匹配b规则'] print('<<<<<<============================>>>>>>>') ''' 反斜杠后边跟普通字符实现特殊功能;(即预定义字符) 预定义字符是在字符集和组里都是有用的 ''' #\d匹配任何十进制数,它相当于类[0-9] print(re.findall("\d", "匹配规则这2个字符串3是否匹配规则5则则则7则"))#['2', '3', '5', '7'] #\d+如果需要匹配一位或者多位数的数字时用 print(re.findall("\d+", "匹配规则这2个字符串134444是否匹配规则5则则则7则") )#['2', '134444', '5', '7'] #\D匹配任何非数字字符,它相当于类[^0-9] print(re.findall("\D", "匹则这2个串3是否5则7则"))#['匹', '则', '这', '个', '串', '是', '否', '则', '则'] #\s匹配任何空白字符,它相当于类[\t\n\r\f\v] print(re.findall("\s", "匹配规则 这2个字符串3是否匹\n配规则5则则则7则"))#[' ', ' ', ' ', '\n'] #\S匹配任何非空白字符,它相当于类[^\t\n\r\f\v] print(re.findall("\S", "匹则 这2串3匹\n配则7则"))#['匹', '则', '这', '2', '串', '3', '匹', '配', '则', '7', '则'] #\w匹配包括下划线在内任何字母数字字符,它相当于类[a-zA-Z0-9_] print(re.findall('\w',"hps://ww.c12b.c/"))#['h', 'p', 's', 'w', 'w', 'c', '1', '2', 'b', 'c'] #\W匹配非任何字母数字字符包括下划线在内,它相当于类[^a-zA-Z0-9_] print(re.findall('\W',"hps://ww.c12b.c/"))#[':', '/', '/', '.', '.', '/'] ''' ()元字符,分组:也就是分组匹配,()里面的为一个组也可以理解成一个整体 如果()后面跟的是特殊元字符如 (adc)* 那么*控制的前导字符就是()里的整体内容,不再是前导一个字符''' print(re.search("(a4)+", "a4a4a4a4a4dg4g654gb").group())#a4a4a4a4a4 print(re.search("a(\d+)", "a466666664a4a4a4dg4g654gb").group())#a466666664 #|元字符,或 |或,或就是前后其中一个符合就匹配 print(re.findall(r"你|好", "a4a4a你4aabc4a4dgg好dg4g654g"))#['你', '好'] ''' r原生字符: 将在python里有特殊意义的字符如\b,转换成原生字符(就是去除它在python的特殊意义), 不然会给正则表达式有冲突,为了避免这种冲突可以在规则前加原始字符r '''
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
''' match()函数(以后常用) match,从头匹配一个符合规则的字符串,从起始位置开始匹配,匹配成功返回一个对象,未匹配成功返回None match(pattern, string, flags=0) # pattern: 正则模型 # string : 要匹配的字符串 # falgs : 匹配模式 注意:match()函数 与 search()函数基本是一样的功能,不一样的就是match()匹配字符串开始位置的一个符合规则的字符串, search()是在字符串全局匹配第一个合规则的字符串 ?P<n1> #?P<>定义组里匹配内容的key(键),<>里面写key名称,值就是匹配到的内容(只对正则函数返回对象的有用) 取出匹配对象方法,只对正则函数返回对象的有用 group() # 获取匹配到的所有结果,不管有没有分组将匹配到的全部拿出来,有参取匹配到的第几个如2 groups() # 获取模型中匹配到的分组结果,只拿出匹配到的字符串中分组部分的结果 groupdict() # 获取模型中匹配到的分组结果,只拿出匹配到的字符串中分组部分定义了key的组结果 ''' import re origin = "hello egon bcd egon lge egon acd 19" #无分组 r1 = re.match("h\w+", origin) print(r1.group())#hello print(r1.groups())#() print(r1.groupdict())#{} #有分组 r2 = re.match("h(\w+)", origin) print(r2.group())#hello print(r2.groups())#('ello',) print(r2.groupdict())#{} r3 =re.match("(?P<n1>h)(?P<n2>\w+)", origin) print(r3.group())#hello print(r3.groups())#('h', 'ello') print(r3.groupdict())#{'n2': 'ello', 'n1': 'h'}
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
''' search()函数 search,浏览全部字符串,匹配第一符合规则的字符串,浏览整个字符串去匹配第一个,未匹配成功返回None search(pattern, string, flags=0) # pattern: 正则模型 # string : 要匹配的字符串 # falgs : 匹配模式 注意:match()函数 与 search()函数基本是一样的功能, 不一样的就是match()匹配字符串开始位置的一个符合规则的字符串,search()是在字符串全局匹配第一个合规则的字符串 ''' import re origin = "hello alex bcd alex lge alex acd 19" #无分组 r = re.search("a\w+", origin) print(r.group())#alex print(r.groups())#() print(r.groupdict())#{} #有分组 r = re.search("a(\w+).*(\d)", origin) print(r.group())#alex bcd alex lge alex acd 19 print(r.groups())#('lex', '9') print(r.groupdict())#{} r = re.search("a(?P<n1>\w+).*(?P<n2>\d)", origin) print(r.group())#alex bcd alex lge alex acd 19 print(r.groups())#('lex', '9') print(r.groupdict())#{'n1': 'lex', 'n2': '9'}
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
'''findall()函数(以后常用) findall(pattern, string, flags=0) # pattern: 正则模型 # string : 要匹配的字符串 # falgs : 匹配模式 浏览全部字符串,匹配所有合规则的字符串,匹配到的字符串放到一个列表中,未匹配成功返回空列表 注意:一旦匹配成,再次匹配,是从前一次匹配成功的,后面一位开始的,也可以理解为匹配成功的字符串,不在参与下次匹配''' import re str = "a2b3c4d5" print(re.findall("\d+\w\d+",str))#['2b3', '4d5'] print(re.findall("",str))#['', '', '', '', '', '', '', '', ''] #注意:如果没写匹配规则,也就是空规则,返回的是一个比原始字符串多一位的,空字符串列表 origin = "hello alex bcd alex lge alex acd 19" print(re.findall("a\w+", origin) )#['alex', 'alex', 'alex', 'acd'] print(re.findall("a(\w+)", origin) )#['lex', 'lex', 'lex', 'cd'] # 有分组:只将匹配到的字符串里,组的部分放到列表里返回,相当于groups()方法 print(re.findall("a(?:\w+)", origin))#['alex', 'alex', 'alex', 'acd'] #?:在有分组的情况下,不只拿分组里的字符串,拿所有匹配到的字符串,注意?:只用于不是返回正则对象的函数如findall() print(re.findall("(a)(\w+)", origin))#[('a', 'lex'), ('a', 'lex'), ('a', 'lex'), ('a', 'cd')] #多个分组:只将匹配到的字符串里,组的部分放到一个元组中,最后将所有元组放到一个列表里返 #相当于在group()结果里再将组的部分,分别,拿出来放入一个元组,最后将所有元组放入一个列表返回 print(re.findall("(a)(\w+(e))", origin))#[('a', 'le', 'e'), ('a', 'le', 'e'), ('a', 'le', 'e')] ''' 多个分组:只将匹配到的字符串里,组的部分放到一个元组中,最后将所有元组放到一个列表里返 相当于在group()结果里再将组的部分,分别,拿出来放入一个元组,最后将所有元组放入一个列表返回 '''
r原生字符
将在python里有特殊意义的字符如\b,转换成原生字符(就是去除它在python的特殊意义),不然会给正则表达式有冲突,
为了避免这种冲突可以在规则前加原始字符r
二、
正则表达式,返回类型为表达式对象的
如:<_sre.SRE_Match object; span=(6, 7), match='a'>
返回对象的,需要用正则方法取字符串,
方法有
group() # 获取匹配到的所有结果,不管有没有分组将匹配到的全部拿出来,有参取匹配到的第几个如2
groups() # 获取模型中匹配到的分组结果,只拿出匹配到的字符串中分组部分的结果
groupdict() # 获取模型中匹配到的分组结果,只拿出匹配到的字符串中分组部分定义了key的组结果
三、
匹配到的字符串里出现空字符
注意:正则匹配到空字符的情况,如果规则里只有一个组,而组后面是*就表示组里的内容可以是0个或者多过,这样组里就有了两个意思,
一个意思是匹配组里的内容,二个意思是匹配组里0内容(即是空白)所以尽量避免用*否则会有可能匹配出空字符串
四、()分组
注意:分组的意义,就是在匹配成功的字符串中,在提取()里,组里面的字符串
五、
?:在有分组的情况下findall()函数,不只拿分组里的字符串,拿所有匹配到的字符串,
注意?:只用于不是返回正则对象的函数如findall()
12、logging模块
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
''' 1、logging介绍: DEBUG: 最详细的日志信息,典型应用场景是 问题诊断 INFO: 信息详细程度仅次于DEBUG,通常只记录关键节点信息,用于确认一切都是按照我们预期的那样进行工作 WARNING: 当某些不期望的事情发生时记录的信息(如,磁盘可用空间较低),但是此时应用程序还是正常运行的 ERROR: 由于一个更严重的问题导致某些功能不能正常运行时记录的信息 CRITICAL: 当发生严重错误,导致应用程序不能继续运行时记录的信息 日志级别顺序:DEBUG < INFO < WARNING < ERROR < CRITICAL 日志级别应用场景: 开发应用程序或部署开发环境时,可以使用DEBUG或INFO级别的日志获取尽可能详细的日志信息来进行开发或部署调试; 应用上线或部署生产环境时,应该使用WARNING或ERROR或CRITICAL级别的日志来降低机器的I/O压力和提高获取错误日志信息的效率。 日志级别的指定通常都是在应用程序的配置文件中进行指定的。 注意: 当为某个应用程序指定一个日志级别后,应用程序会记录所有日志级别大于或等于指定日志级别的日志信息, 而不是仅仅记录指定级别的日志信息,nginx、php等应用程序以及这里的python的logging模块都是这样的。 同样,logging模块也可以指定日志记录器的日志级别,只有级别大于或等于该指定日志级别的日志记录才会被输出, 小于该等级的日志记录将会被丢弃 2、logging模块的使用方式介绍 logging模块提供了两种记录日志的方式: 第一种方式是使用logging提供的模块级别的函数 第二种方式是使用Logging日志系统的四大组件 其实,logging所提供的模块级别的日志记录函数也是对logging日志系统相关类的封装而已。 logging模块定义的模块级别的常用函数 函数 说明 logging.debug(msg, *args, **kwargs) 创建一条严重级别为DEBUG的日志记录 logging.info(msg, *args, **kwargs) 创建一条严重级别为INFO的日志记录 logging.warning(msg, *args, **kwargs) 创建一条严重级别为WARNING的日志记录 logging.error(msg, *args, **kwargs) 创建一条严重级别为ERROR的日志记录 logging.critical(msg, *args, **kwargs) 创建一条严重级别为CRITICAL的日志记录 logging.log(level, *args, **kwargs) 创建一条严重级别为level的日志记录 logging.basicConfig(**kwargs) 对root logger进行一次性配置 其中logging.basicConfig(**kwargs)函数用于指定“要记录的日志级别”、“日志格式”、“日志输出位置”、“日志文件的打开模式 ''' import logging #简单配置 logging.debug("debug_msg") logging.info("info_msg") logging.warning("warning_msg") logging.error("error_msg") logging.critical("critical_msg") ''' WARNING:root:warning_msg ERROR:root:error_msg CRITICAL:root:critical_msg 输出内容描述: 默认情况下Python的logging模块将日志打印到了标准输出中, 且只显示了大于等于WARNING级别的日志,这说明默认的日志级别设置为WARNING 日志级别等级CRITICAL > ERROR > WARNING > INFO > DEBUG 默认输出格式为:默认的日志格式为日志级别:Logger名称:用户输出消息 ''' logging.basicConfig(level=logging.DEBUG, format="%(asctime)s %(name)s %(levelname)s %(message)s", datefmt = '%Y-%m-%d %H:%M:%S %a') logging.debug("debug_msg1") logging.info("info_msg1") logging.warning("warning_ms1") logging.error("error_msg1") logging.critical("critical_msg1") ''' 2018-08-29 10:45:07 Wed root DEBUG debug_msg1 2018-08-29 10:45:07 Wed root INFO info_msg1 2018-08-29 10:45:07 Wed root WARNING warning_ms1 2018-08-29 10:45:07 Wed root ERROR error_msg1 2018-08-29 10:45:07 Wed root CRITICAL critical_msg1 ''' ''' logging.basicConfig()函数包含参数说明 参数名称 描述 filename 指定日志输出目标文件的文件名(可以写文件名也可以写文件的完整的绝对路径,写文件名日志放执行文件目录下, 写完整路径按照完整路径生成日志文件),指定该设置项后日志信心就不会被输出到控制台了 filemode 指定日志文件的打开模式,默认为'a'。需要注意的是,该选项要在filename指定时才有效 format 指定日志格式字符串,即指定日志输出时所包含的字段信息以及它们的顺序。 logging模块定义的格式字段下面会列出。 datefmt 指定日期/时间格式。需要注意的是,该选项要在format中包含时间字段%(asctime)s时才有效 level 指定日志器的日志级别 stream 指定日志输出目标stream,如sys.stdout、sys.stderr以及网络stream。 需要说明的是,stream和filename不能同时提供,否则会引发 ValueError异常 style Python 3.2中新添加的配置项。指定format格式字符串的风格,可取值为'%'、'{'和'$',默认为'%' handlers Python 3.3中新添加的配置项。该选项如果被指定,它应该是一个创建了多个Handler的可迭代对象, 这些handler将会被添加到root logger。 需要说明的是:filename、stream和handlers 这三个配置项只能有一个存在,不能同时出现2个或3个,否则会引发ValueError异常。 logging模块中定义好的可以用于format格式字符串说明 字段/属性名称 使用格式 描述 asctime %(asctime)s将日志的时间构造成可读的形式,默认情况下是‘2016-02-08 12:00:00,123’精确到毫秒 name %(name)s 所使用的日志器名称,默认是'root',因为默认使用的是 rootLogger filename %(filename)s 调用日志输出函数的模块的文件名; pathname的文件名部分,包含文件后缀 funcName %(funcName)s 由哪个function发出的log, 调用日志输出函数的函数名 levelname %(levelname)s 日志的最终等级(被filter修改后的) message %(message)s 日志信息, 日志记录的文本内容 lineno %(lineno)d 当前日志的行号, 调用日志输出函数的语句所在的代码行 levelno %(levelno)s 该日志记录的数字形式的日志级别(10, 20, 30, 40, 50) pathname %(pathname)s 完整路径 ,调用日志输出函数的模块的完整路径名,可能没有 process %(process)s 当前进程, 进程ID。可能没有 processName %(processName)s 进程名称,Python 3.1新增 thread %(thread)s 当前线程, 线程ID。可能没有 threadName %(thread)s 线程名称 module %(module)s 调用日志输出函数的模块名filename的名称部分,不包含后缀即不包含文件后缀的文件名 created %(created)f 当前时间,用UNIX标准的表示时间的浮点数表示; 日志事件发生的时间--时间戳,就是当时调用time.time()函数返回的值 relativeCreated %(relativeCreated)d 输出日志信息时的,自Logger创建以 来的毫秒数; 日志事件发生的时间相对于logging模块加载时间的相对毫秒数 msecs %(msecs)d 日志事件发生事件的毫秒部分。 logging.basicConfig()中用了参数datefmt,将会去掉asctime中产生的毫秒部分,可以用这个加上 ''' LOG_FORMAT = "%(asctime)s %(name)s %(levelname)s %(pathname)s %(message)s "#配置输出日志格式 DATE_FORMAT = '%Y-%m-%d %H:%M:%S %a ' #配置输出时间的格式,注意月份和天数不要搞乱了 logging.basicConfig(level=logging.DEBUG, format=LOG_FORMAT, datefmt = DATE_FORMAT , filename=r"f:\test.log" #有了filename参数就不会直接输出显示到控制台,而是直接写入文件 ) logging.debug("msg1") logging.info("msg2") logging.warning("msg3") logging.error("msg4") logging.critical("msg5") ''' 2018-08-29 11:12:00 Wed root DEBUG F:/PycharmProjects/untitled/Day8/logging模块.py msg1 2018-08-29 11:12:00 Wed root INFO F:/PycharmProjects/untitled/Day8/logging模块.py msg2 2018-08-29 11:12:00 Wed root WARNING F:/PycharmProjects/untitled/Day8/logging模块.py msg3 2018-08-29 11:12:00 Wed root ERROR F:/PycharmProjects/untitled/Day8/logging模块.py msg4 2018-08-29 11:12:00 Wed root CRITICAL F:/PycharmProjects/untitled/Day8/logging模块.py msg5 '''
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
''' logging.debug()、logging.info()、logging.warning()、logging.error()、logging.critical()(分别用以记录不同级别的日志信息) logging.basicConfig()(用默认日志格式(Formatter)为日志系统建立一个默认的流处理器(StreamHandler), 设置基础配置(如日志级别等)并加到root logger(根Logger)中)这几个logging模块级别的函数。 第二种是一个模块级别的函数是logging.getLogger([name])(返回一个logger对象,如果没有指定名字将返回root logger)。 logging日志模块四大组件:在介绍logging模块的日志流处理流程之前,我们先来介绍下logging模块的四大组件: 组件名称 对应类名 功能描述 日志器 Logger 提供了应用程序可一直使用的接口 处理器 Handler 将logger创建的日志记录发送到合适的目的输出 过滤器 Filter 提供了更细粒度的控制工具来决定输出哪条日志记录,丢弃哪条日志记录 格式器 Formatter 决定日志记录的最终输出格式 logging模块就是通过这些组件来完成日志处理的,上面所使用的logging模块级别的函数也是通过这些组件对应的类来实现的。 这些组件之间的关系描述: 日志器(logger)需要通过处理器(handler)将日志信息输出到目标位置,如:文件、sys.stdout、网络等; 不同的处理器(handler)可以将日志输出到不同的位置; 日志器(logger)可以设置多个处理器(handler)将同一条日志记录输出到不同的位置; 每个处理器(handler)都可以设置自己的过滤器(filter)实现日志过滤,从而只保留感兴趣的日志; 每个处理器(handler)都可以设置自己的格式器(formatter)实现同一条日志以不同的格式输出到不同的地方。 简单点说就是:日志器(logger)是入口,真正干活儿的是处理器(handler),处理器(handler) 还可以通过过滤器(filter)和格式器(formatter)对要输出的日志内容做过滤和格式化等处理操作。 logging日志模块相关类及其常用方法介绍:与logging四大组件相关的类:Logger, Handler, Filter, Formatter。 Logger类 Logger对象有3个任务要做: 1)向应用程序代码暴露几个方法,使应用程序可以在运行时记录日志消息; 2)基于日志严重等级(默认的过滤设施)或filter对象来决定要对哪些日志进行后续处理; 3)将日志消息传送给所有感兴趣的日志handlers。 Logger对象最常用的方法分为两类:配置方法 和 消息发送方法 最常用的配置方法如下: 方法 描述 Logger.setLevel() 设置日志器将会处理的日志消息的最低严重级别 Logger.addHandler() 和 Logger.removeHandler() 为该logger对象添加 和 移除一个handler对象 Logger.addFilter() 和 Logger.removeFilter() 为该logger对象添加 和 移除一个filter对象 logger对象配置完成后,可以使用下面的方法来创建日志记录: 方法 描述 Logger.debug()info()warning()error()critical() 创建一个与它们的方法名对应等级的日志记录 Logger.exception() 创建一个类似于Logger.error()的日志消息 Logger.log() 需要获取一个明确的日志level参数来创建一个日志记录 一个Logger对象呢?一种方式是通过Logger类的实例化方法创建一个Logger类的实例, 但是我们通常都是用第二种方式--logging.getLogger()方法。 logging.getLogger()方法有一个可选参数name, 该参数表示将要返回的日志器的名称标识,如果不提供该参数,则其值为'root'。 若以相同的name参数值多次调用getLogger()方法,将会返回指向同一个logger对象的引用。 多次使用注意不能创建多个logger,否则会出现重复输出日志现象。 关于logger的层级结构与有效等级的说明: logger的名称是一个以'.'分割的层级结构,每个'.'后面的logger都是'.'前面的logger的children, 例如,有一个名称为 foo 的logger,其它名称分别为 foo.bar, foo.bar.baz 和 foo.bam都是 foo 的后代。 logger有一个"有效等级(effective level)"的概念 如果一个logger上没有被明确设置一个level,那么该logger就是使用它parent的level; 如果它的parent也没有明确设置level则继续向上查找parent的parent的有效level, 依次类推,直到找到个一个明确设置了level的祖先为止。需要说明的是,root logger总是会有一个明确的level设置(默认为 WARNING) 当决定是否去处理一个已发生的事件时,logger的有效等级将会被用来决定是否将该事件传递给该logger的handlers进行处理。 child loggers在完成对日志消息的处理后,默认会将日志消息传递给与它们的祖先loggers相关的handlers。 因此,我们不必为一个应用程序中所使用的所有loggers定义和配置handlers,只需要为一个顶层的logger配置handlers, 然后按照需要创建child loggers就可足够了。我们也可以通过将一个logger的propagate属性设置为False来关闭这种传递机制。 Handler类 Handler对象的作用是(基于日志消息的level)将消息分发到handler指定的位置(文件、网络、邮件等)。 Logger对象可以通过addHandler()方法为自己添加0个或者更多个handler对象。比如,一个应用程序可能想要实现以下几个日志需求: 1)把所有日志都发送到一个日志文件中; 2)把所有严重级别大于等于error的日志发送到stdout(标准输出); 3)把所有严重级别为critical的日志发送到一个email邮件地址。 这种场景就需要3个不同的handlers,每个handler复杂发送一个特定严重级别的日志到一个特定的位置。 Handler.setLevel(lel):指定被处理的信息级别,低于lel级别的信息将被忽略 Handler.setFormatter():给这个handler选择一个格式 Handler.addFilter(filt)、Handler.removeFilter(filt):新增或删除一个filter对象 需要说明的是,应用程序代码不应该直接实例化和使用Handler实例。 因为Handler是一个基类,它只定义了素有handlers都应该有的接口,同时提供了一些子类可以直接使用或覆盖的默认行为。 下面是一些常用的Handler: Handler 描述 logging.StreamHandler 将日志消息发送到输出到Stream,如std.out, std.err或任何file-like对象。 logging.FileHandler 将日志消息发送到磁盘文件,默认情况下文件大小会无限增长 logging.handlers.RotatingFileHandler 将日志消息发送到磁盘文件,并支持日志文件按大小切割 logging.hanlders.TimedRotatingFileHandler 将日志消息发送到磁盘文件,并支持日志文件按时间切割 logging.handlers.HTTPHandler 将日志消息以GET或POST的方式发送给一个HTTP服务器 logging.handlers.SMTPHandler 将日志消息发送给一个指定的email地址 logging.NullHandler 该Handler实例会忽略error messages,通常被想使用logging的library开发者使用来 避免'No handlers could be found for logger XXX'信息的出现。 Formater类 Formater对象用于配置日志信息的最终顺序、结构和内容。 与logging.Handler基类不同的是,应用代码可以直接实例化Formatter类。 另外,如果你的应用程序需要一些特殊的处理行为,也可以实现一个Formatter的子类来完成。 Formatter类的构造方法定义如下: logging.Formatter.__init__(fmt=None, datefmt=None, style='%') 可见,该构造方法接收3个可选参数: fmt:指定消息格式化字符串,如果不指定该参数则默认使用message的原始值 datefmt:指定日期格式字符串,如果不指定该参数则默认使用"%Y-%m-%d %H:%M:%S" style:Python 3.2新增的参数,可取值为 '%', '{'和 '$',如果不指定该参数则默认使用'%' 一般直接用logging.Formatter(fmt, datefmt) Filter类(暂时了解) Filter可以被Handler和Logger用来做比level更细粒度的、更复杂的过滤功能。 Filter是一个过滤器基类,它只允许某个logger层级下的日志事件通过过滤。该类定义如下: class logging.Filter(name='') filter(record) 比如,一个filter实例化时传递的name参数值为'A.B',那么该filter实例将只允许名称为类似如下规则的loggers产生的日志记录 通过过滤:'A.B','A.B,C','A.B.C.D','A.B.D',而名称为'A.BB', 'B.A.B'的loggers产生的日志则会被过滤掉。 如果name的值为空字符串,则允许所有的日志事件通过过滤。 filter方法用于具体控制传递的record记录是否能通过过滤,如果该方法返回值为0表示不能通过过滤,返回值为非0表示可以通过过滤。 说明: 如果有需要,也可以在filter(record)方法内部改变该record,比如添加、删除或修改一些属性。 我们还可以通过filter做一些统计工作,比如可以计算下被一个特殊的logger或handler所处理的record数量等。 ''' ''' 日志流处理简要流程 1、创建一个logger 2、设置下logger的日志的等级 3、创建合适的Handler(FileHandler要有路径) 4、设置下每个Handler的日志等级 5、创建下日志的格式 6、向Handler中添加上面创建的格式 7、将上面创建的Handler添加到logger中 8、打印输出logger.debug\logger.info\logger.warning\logger.error\logger.critical ''' import logging def log(msg): logger = logging.getLogger("logging") logger.setLevel(logging.DEBUG) fh = logging.FileHandler('test.log',encoding='utf-8') ch = logging.StreamHandler() formatter = logging.Formatter( fmt="%(asctime)s %(name)s %(filename)s %(message)s",datefmt="%Y/%m/%d %X" ) fh.setFormatter(formatter) ch.setFormatter(formatter) logger.addHandler(fh) logger.addHandler(ch) logger.info(msg) # 解决方案 添加removeHandler语句,每次用完之后移除Handler logger.removeHandler(fh) logger.removeHandler(ch) # logger.warning("泰拳警告") # logger.info("提示") # logger.error("错误") log("小明") log("小民")
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
import logging def log(): logger = logging.getLogger("dashuang.gu") logger.setLevel(logging.DEBUG) if not logger.handlers: fh = logging.FileHandler('example.log',encoding='utf-8') ch = logging.StreamHandler() formatter = logging.Formatter(fmt="%(asctime)s %(name)s %(filename)s %(message)s",datefmt="%Y/%m/%d %X") fh.setFormatter(formatter) ch.setFormatter(formatter) logger.addHandler(fh) logger.addHandler(ch) return logger logger = log() logger.debug('查错') logger.info('错误') logger.warning('一般') logger.error('严重') logger.critical('shutdown')