第三方模块
一,time模块
- 时间戳(timestamp):通常来说,时间戳表示的是从1970年1月1日00:00:00开始按秒计算的偏移量。我们运行“type(time.time())”,返回的是float类型。
- 作用:用于计算时间间隔的计算
- 格式化的时间字符串(Format String)
- 作用:展示时间
- 结构化的时间(struct_time):struct_time元组共有9个元素共九个元素:(年,月,日,时,分,秒,一年中第几周,一年中第几天,夏令时)
- 作用:用于展示部分时间
1 import time 2 print(time.time())#时间戳 3 print(time.strftime("%Y-%m-%d %H:%M:%S %p"))#这个H可以换成I代表十二小时制,M代表二十四小时制,p代表上午与下午 4 print(time.strftime("%Y-%m-%d %X")) #这个X与上面的%H:%M:%S是相同含义,这两个很重要
结构化时间1 import time 2 res=time.localtime() #本地时区的struct_time 3 print(res) 4 print(res.tm_year)
- 作用:用于展示部分时间
进阶版:daetime模块
1 import datetime 2 print(datetime.datetime.now()) #直接展示当前时间 3 print(datetime.date.today()+datetime.timedelta(days=1)) #直接进行加减

1 #--------------------------按图1转换时间 2 # localtime([secs]) 3 # 将一个时间戳转换为当前时区的struct_time。secs参数未提供,则以当前时间为准。 4 time.localtime() 5 time.localtime(1473525444.037215) 6 7 # gmtime([secs]) 和localtime()方法类似,gmtime()方法是将一个时间戳转换为UTC时区(0时区)的struct_time。 8 9 # mktime(t) : 将一个struct_time转化为时间戳。 10 print(time.mktime(time.localtime()))#1473525749.0 11 12 13 # strftime(format[, t]) : 把一个代表时间的元组或者struct_time(如由time.localtime()和 14 # time.gmtime()返回)转化为格式化的时间字符串。如果t未指定,将传入time.localtime()。如果元组中任何一个 15 # 元素越界,ValueError的错误将会被抛出。 16 print(time.strftime("%Y-%m-%d %X", time.localtime()))#2016-09-11 00:49:56 17 18 # time.strptime(string[, format]) 19 # 把一个格式化时间字符串转化为struct_time。实际上它和strftime()是逆操作。 20 print(time.strptime('2011-05-05 16:37:06', '%Y-%m-%d %X')) 21 #time.struct_time(tm_year=2011, tm_mon=5, tm_mday=5, tm_hour=16, tm_min=37, tm_sec=6, 22 # tm_wday=3, tm_yday=125, tm_isdst=-1) 23 #在这个函数中,format默认为:"%a %b %d %H:%M:%S %Y"。

了解知识
1 import datetime 2 print(datetime.datetime.fromtimestamp(2233333)) #直接将时间戳转化为标准格式
二,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)) #代表ASCill验证码a-z 6 s2=str(random.randint(0,9)) 7 res+=random.choice([s1,s2]) 8 return res 9 10 print(make_code(9))
三,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的大小
1 在Linux和Mac平台上,该函数会原样返回path,在windows平台上会将路径中所有字符转换为小写,并将所有斜杠转换为饭斜杠。 2 >>> os.path.normcase('c:/windows\\system32\\') 3 'c:\\windows\\system32\\' 4 5 6 规范化路径,如..和/ 7 >>> os.path.normpath('c://windows\\System32\\../Temp/') 8 'c:\\windows\\Temp' 9 10 >>> a='/Users/jieli/test1/\\\a1/\\\\aa.py/../..' 11 >>> print(os.path.normpath(a)) 12 /Users/jieli/test1
路径处理:
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 返回操作系统平台名称
重点掌握第1,5个
五,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[, onerror]])
递归的去删除文件
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模块,有关序列化的模块
前期知识准备:
序列化:
内存中的数据模型--->序列化--->特定的格式(json格式或picket格式)
反序列化:
内存中的数据模型<---序列化<---特定的格式(json格式或picket格式)
序列化作用:
-
-
- 用于储存,常用的是pickle模块
-
内存是无法永久保存数据的,当程序运行了一段时间,我们断电或者重启程序,内存中关于这个程序的之前一段时间的数据(有结构)都被清空了。
在断电或重启程序之前将程序当前内存中所有的数据都保存下来(保存到文件中),以便于下次程序执行能够从文件中载入之前的数据,然后继续执行,这就是序列化。
具体的来说,你玩使命召唤闯到了第13关,你保存游戏状态,关机走人,下次再玩,还能从上次的位置开始继续闯关。或如,虚拟机状态的挂起等。
-
- 用于夸平台、跨语言的数据交互,常用的是json模块
- 有时候写功能时,可能需要不同语言的结果进行交互,此时就需要一种中间结构的数据进行传输
- 强调:虽然理论上json模块也可以用于储存,但是具有局限性,比如里面就没有集合的形式
- json中的格式与python中有很类似的,但是还是不同的,注意区分
-
![]()
- 用于储存,常用的是pickle模块
-
具体操作:
1 s=[1,2,3,'aaa',['1',2,'b']] 2 import json 3 #序列化的复杂方法 4 with open('test.txt',mode='wt',encoding='utf-8') as f: 5 pre=json.dumps(s) 6 f.write(pre) 7 # 序列化的简单方法 8 json.dump(s,f) 9 反序列化也是类似的
注意点:
-
-
无论数据是怎样创建的,只要满足json格式,就可以json.loads出来,不一定非要dumps的数据才能loads
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))
-
在python解释器2.7与3.6之后都可以json.loads(bytes类型),但唯独3.5不可以
1 >>> import json 2 >>> json.loads(b'{"a":111}') 3 Traceback (most recent call last): 4 File "<stdin>", line 1, in <module> 5 File "/Users/linhaifeng/anaconda3/lib/python3.5/json/__init__.py", line 312, in loads 6 s.__class__.__name__)) 7 TypeError: the JSON object must be str, not 'bytes'
-
猴子补丁,就是在原模块中对某一功能进行覆盖,不对原功能进行抹除。
特点是如果之前即使进行了引用此次改动也不会影响到之前的。
1 只需要在入口处加上 2 , 只需要在入口加上: 3 4 import json 5 import ujson 6 7 def monkey_patch_json(): 8 json.__name__ = 'ujson' 9 json.dumps = ujson.dumps 10 json.loads = ujson.loads 11 12 monkey_patch_json() # 之所以在入口处加,是因为模块在导入一次后,后续的导入便直接引用第一次的成果 13 14 #其实这种场景也比较多, 比如我们引用团队通用库里的一个模块, 又想丰富模块的功能, 除了继承之外也可以考虑用Monkey 15 Patch.采用猴子补丁之后,如果发现ujson不符合预期,那也可以快速撤掉补丁。个人感觉Monkey 16 Patch带了便利的同时也有搞乱源代码的风险!
七, shelve模块(了解)与xml模块(了解)
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'])
f.close()
xml是实现不同语言或程序之间进行数据交换的协议,跟json差不多,但json使用起来更简单,不过,古时候,在json还没诞生的黑暗年代,大家只能选择用xml呀,至今很多传统公司如金融行业的很多系统的接口还主要是xml。
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协议在各个语言里的都 是支持的,在python中可以用以下模块操作xml:
# print(root.iter('year')) #全文搜索
# print(root.find('country')) #在root的子节点找,只找一个
# print(root.findall('country')) #在root的子节点找,找所有
import xml.etree.ElementTree as ET
tree = ET.parse("xmltest.xml")
root = tree.getroot()
print(root.tag)
#遍历xml文档
for child in root:
print('========>',child.tag,child.attrib,child.attrib['name'])
for i in child:
print(i.tag,i.attrib,i.text)
#只遍历year 节点
for node in root.iter('year'):
print(node.tag,node.text)
#---------------------------------------
import xml.etree.ElementTree as ET
tree = ET.parse("xmltest.xml")
root = tree.getroot()
#修改
for node in root.iter('year'):
new_year=int(node.text)+1
node.text=str(new_year)
node.set('updated','yes')
node.set('version','1.0')
tree.write('test.xml')
#删除node
for country in root.findall('country'):
rank = int(country.find('rank').text)
if rank > 50:
root.remove(country)
tree.write('output.xml')
#在country内添加(append)节点year2
import xml.etree.ElementTree as ET
tree = ET.parse("a.xml")
root=tree.getroot()
for country in root.findall('country'):
for year in country.findall('year'):
if int(year.text) > 2000:
year2=ET.Element('year2')
year2.text='新年'
year2.attrib={'update':'yes'}
country.append(year2) #往country节点下添加子节点
tree.write('a.xml.swap')
自己创建xml文档:
1 import xml.etree.ElementTree as ET 2 3 4 new_xml = ET.Element("namelist") 5 name = ET.SubElement(new_xml,"name",attrib={"enrolled":"yes"}) 6 age = ET.SubElement(name,"age",attrib={"checked":"no"}) 7 sex = ET.SubElement(name,"sex") 8 sex.text = '33' 9 name2 = ET.SubElement(new_xml,"name",attrib={"enrolled":"no"}) 10 age = ET.SubElement(name2,"age") 11 age.text = '19' 12 13 et = ET.ElementTree(new_xml) #生成文档对象 14 et.write("test.xml", encoding="utf-8",xml_declaration=True) 15 16 ET.dump(new_xml) #打印生成的格式
八,configparser模块,有关配置文件的模块
1 # 注释1 2 ; 注释2 3 4 [section1] #代表一部分的意思 5 k1 = v1 6 k2:v2 7 user=egon 8 age=18 9 is_admin=true 10 salary=31 11 12 [section2] 13 k1 = v1
读取
1 import configparser 2 3 config=configparser.ConfigParser() 4 config.read('a.cfg') 5 6 #查看所有的标题 7 res=config.sections() #['section1', 'section2'] 8 print(res) 9 10 #查看标题section1下所有key=value的key 11 options=config.options('section1') 12 print(options) #['k1', 'k2', 'user', 'age', 'is_admin', 'salary'] 13 14 #查看标题section1下所有key=value的(key,value)格式 15 item_list=config.items('section1') 16 print(item_list) #[('k1', 'v1'), ('k2', 'v2'), ('user', 'egon'), ('age', '18'), ('is_admin', 'true'), ('salary', '31')] 17 18 #查看标题section1下user的值=>字符串格式 19 val=config.get('section1','user') 20 print(val) #egon 21 22 #查看标题section1下age的值=>整数格式 23 val1=config.getint('section1','age') 24 print(val1) #18 25 26 #查看标题section1下is_admin的值=>布尔值格式 27 val2=config.getboolean('section1','is_admin') 28 print(val2) #True 29 30 #查看标题section1下salary的值=>浮点型格式 31 val3=config.getfloat('section1','salary') 32 print(val3) #31.0
改写,一般改写是用户的事情
1 import configparser 2 3 config=configparser.ConfigParser() 4 config.read('a.cfg',encoding='utf-8') 5 6 7 #删除整个标题section2 8 config.remove_section('section2') 9 10 #删除标题section1下的某个k1和k2 11 config.remove_option('section1','k1') 12 config.remove_option('section1','k2') 13 14 #判断是否存在某个标题 15 print(config.has_section('section1')) 16 17 #判断标题section1下是否有user 18 print(config.has_option('section1','')) 19 20 21 #添加一个标题 22 config.add_section('egon') 23 24 #在标题egon下添加name=egon,age=18的配置 25 config.set('egon','name','egon') 26 config.set('egon','age',18) #报错,必须是字符串 27 28 29 #最后将修改的内容写入文件,完成最终的修改 30 config.write(open('a.cfg','w'))
九,hashlib模块
准备知识:
1,hash是一类算法,该算法接受传入的内容经过运算得到的一串hash值
2,特点
-
-
- 只要传入的内容一样,得到的hash值就一样
- 应用点:可以检验下载的内容是否一样、文件是否被篡改
- 不能hash值反解内容
- 用于密码变成暗文
- 只要使用的hash算法不变,无论内容有多大,达到的hash长度是固定的
- 只要传入的内容一样,得到的hash值就一样
-
具体使用:hash算法就像一座工厂,工厂接收你送来的原材料(可以用m.update()为工厂运送原材料),经过加工返回的产品就是hash值

1 import hashlib 2 3 m=hashlib.md5()# m=hashlib.sha256() 4 5 m.update('hello'.encode('utf8'))#转化时必须要转为字节类型 6 print(m.hexdigest()) #5d41402abc4b2a76b9719d911017c592 7 8 m.update('alvin'.encode('utf8')) 9 10 print(m.hexdigest()) #92a7e713c30abbb0319fa07da2a5c4af 11 12 m2=hashlib.md5() 13 m2.update('helloalvin'.encode('utf8')) 14 print(m2.hexdigest()) #92a7e713c30abbb0319fa07da2a5c4af 15 16 ''' 17 注意:把一段很长的数据update多次,与一次update这段长数据,得到的结果一样 18 但是update多次为校验大文件提供了可能。 19 '''
1 import hashlib 2 #第一种直接进行转化 3 with open(r'C:\Users\dell',encoding='ab') as f: 4 print(hashlib.md5(f.encode('utf-8')).hexdigest()) 5 #第二种可以防止文件太大导致内存出现问题 6 with open(r'C:\Users\dell',encoding='ab') as f: 7 m='' 8 m=hashlib.md5() 9 for i in f: 10 m.update(i.encode('utf-8')) 11 print(m.hexdigest()) 12 #第三种是随机抽取并进行验证 13
撞库是在一定程度上可以对暗文进行反解,所以可以使用加盐。加盐就是人为的加上一些数据使密码更加的复杂
1 import hashlib 2 #第一种直接进行转化 3 m=hashlib.md5() 4 m.update('hello'.encode('utf-8')) 5 m.update('你好'.encode('utf-8')) #在中间加 6 m.update('world'.encode('utf-8')) 7 print(m.hexdigest())
十,suprocess模块,可以拿到系统运行结果的一种模块
import subprocess 2 #stout,代表正确结果,stderr代表错误结果 3 ''' 4 sh-3.2# ls /Users/egon/Desktop |grep txt$ 5 mysql.txt 6 tt.txt 7 事物.txt 8 ''' 9 10 res1=subprocess.Popen('ls /Users/jieli/Desktop',shell=True,stdout=subprocess.PIPE) 11 res=subprocess.Popen('grep txt$',shell=True,stdin=res1.stdout, 12 stdout=subprocess.PIPE) 13 14 print(res.stdout.read().decode('utf-8')) 15 16 17 #等同于上面,但是上面的优势在于,一个数据流可以和另外一个数据流交互,可以通过爬虫得到结果然后交给grep 18 res1=subprocess.Popen('ls /Users/jieli/Desktop |grep txt$',shell=True,stdout=subprocess.PIPE) 19 print(res1.stdout.read().decode('utf-8')) 20 21 22 #windows下: 23 # dir | findstr 'test*' 24 # dir | findstr 'txt$' 25 import subprocess 26 res1=subprocess.Popen(r'dir C:\Users\Administrator\PycharmProjects\test\函数备课',shell=True,stdout=subprocess.PIPE) 27 res=subprocess.Popen('findstr test*',shell=True,stdin=res1.stdout, 28 stdout=subprocess.PIPE) 29 30 print(res.stdout.read().decode('gbk')) #subprocess使用当前系统默认编码,得到结果为bytes类型,在windows下需要用gbk解码
十一,logging模块
1,日志级别
1 CRITICAL = 50 #FATAL = CRITICAL 2 ERROR = 40 3 WARNING = 30 #WARN = WARNING 4 INFO = 20 5 DEBUG = 10 6 NOTSET = 0 #不设置
2,日志配置,可以直接粘贴复制
1 import logging 2 3 # 一:日志配置 4 logging.basicConfig( 5 # 1、日志输出位置:1、终端 2、文件 6 # filename='access.log', # 不指定,默认打印到终端 7 8 # 2、日志格式 9 format='%(asctime)s - %(name)s - %(levelname)s -%(module)s: %(message)s', 10 11 # 3、时间格式 12 datefmt='%Y-%m-%d %H:%M:%S %p', 13 14 # 4、日志级别 15 # critical => 50 16 # error => 40 17 # warning => 30 18 # info => 20 19 # debug => 10 20 level=30, 21 ) 22 23 # 二:输出日志 24 logging.debug('调试debug') 25 logging.info('消息info') 26 logging.warning('警告warn') 27 logging.error('错误error') 28 logging.critical('严重critical') 29 30 ''' 31 # 注意下面的root是默认的日志名字 32 WARNING:root:警告warn 33 ERROR:root:错误error 34 CRITICAL:root:严重critical 35 '''
3,为logging模块指全局配置,针对所有logger有效,控制打印到文件中
1 可在logging.basicConfig()函数中通过具体参数来更改logging模块默认行为,可用参数有 2 filename:用指定的文件名创建FiledHandler(后边会具体讲解handler的概念),这样日志会被存储在指定的文件中。 3 filemode:文件打开方式,在指定了filename时使用这个参数,默认值为“a”还可指定为“w”。 4 format:指定handler使用的日志显示格式。 5 datefmt:指定日期时间格式。 6 level:设置rootlogger(后边会讲解具体概念)的日志级别 7 stream:用指定的stream创建StreamHandler。可以指定输出到sys.stderr,sys.stdout或者文件,默认为sys.stderr。若同时列出了filename和stream两个参数,则stream参数会被忽略。 8 9 10 11 #格式 12 %(name)s:Logger的名字,并非用户名,详细查看 13 14 %(levelno)s:数字形式的日志级别 15 16 %(levelname)s:文本形式的日志级别 17 18 %(pathname)s:调用日志输出函数的模块的完整路径名,可能没有 19 20 %(filename)s:调用日志输出函数的模块的文件名 21 22 %(module)s:调用日志输出函数的模块名 23 24 %(funcName)s:调用日志输出函数的函数名 25 26 %(lineno)d:调用日志输出函数的语句所在的代码行 27 28 %(created)f:当前时间,用UNIX标准的表示时间的浮 点数表示 29 30 %(relativeCreated)d:输出日志信息时的,自Logger创建以 来的毫秒数 31 32 %(asctime)s:字符串形式的当前时间。默认格式是 “2003-07-08 16:49:45,896”。逗号后面的是毫秒 33 34 %(thread)d:线程ID。可能没有 35 36 %(threadName)s:线程名。可能没有 37 38 %(process)d:进程ID。可能没有 39 40 %(message)s:用户输出的消息 41 42
1 复制代码 2 #======介绍 3 可在logging.basicConfig()函数中可通过具体参数来更改logging模块默认行为,可用参数有 4 filename:用指定的文件名创建FiledHandler(后边会具体讲解handler的概念),这样日志会被存储在指定的文件中。 5 filemode:文件打开方式,在指定了filename时使用这个参数,默认值为“a”还可指定为“w”。 6 format:指定handler使用的日志显示格式。 7 datefmt:指定日期时间格式。 8 level:设置rootlogger(后边会讲解具体概念)的日志级别 9 stream:用指定的stream创建StreamHandler。可以指定输出到sys.stderr,sys.stdout或者文件,默认为sys.stderr。若同时列出了filename和stream两个参数,则stream参数会被忽略。 10 11 12 format参数中可能用到的格式化串: 13 %(name)s Logger的名字 14 %(levelno)s 数字形式的日志级别 15 %(levelname)s 文本形式的日志级别 16 %(pathname)s 调用日志输出函数的模块的完整路径名,可能没有 17 %(filename)s 调用日志输出函数的模块的文件名 18 %(module)s 调用日志输出函数的模块名 19 %(funcName)s 调用日志输出函数的函数名 20 %(lineno)d 调用日志输出函数的语句所在的代码行 21 %(created)f 当前时间,用UNIX标准的表示时间的浮 点数表示 22 %(relativeCreated)d 输出日志信息时的,自Logger创建以 来的毫秒数 23 %(asctime)s 字符串形式的当前时间。默认格式是 “2003-07-08 16:49:45,896”。逗号后面的是毫秒 24 %(thread)d 线程ID。可能没有 25 %(threadName)s 线程名。可能没有 26 %(process)d 进程ID。可能没有 27 %(message)s用户输出的消息 28 29 30 31 32 #========使用 33 import logging 34 logging.basicConfig(filename='access.log', 35 format='%(asctime)s - %(name)s - %(levelname)s -%(module)s: %(message)s', 36 datefmt='%Y-%m-%d %H:%M:%S %p', 37 level=10) 38 39 logging.debug('调试debug') 40 logging.info('消息info') 41 logging.warning('警告warn') 42 logging.error('错误error') 43 logging.critical('严重critical') 44 45 46 47 48 49 #========结果 50 access.log内容: 51 2017-07-28 20:32:17 PM - root - DEBUG -test: 调试debug 52 2017-07-28 20:32:17 PM - root - INFO -test: 消息info 53 2017-07-28 20:32:17 PM - root - WARNING -test: 警告warn 54 2017-07-28 20:32:17 PM - root - ERROR -test: 错误error 55 2017-07-28 20:32:17 PM - root - CRITICAL -test: 严重critical 56 57 part2: 可以为logging模块指定模块级的配置,即所有logger的配置
4,logging模块的Formatter,Handler,Logger,Filter对象 
#logger:产生日志的对象 #Filter:过滤日志的对象 #Handler:接收日志然后控制打印到不同的地方,FileHandler用来打印到文件中,StreamHandler用来打印到终端 #Formatter对象:可以定制不同的日志格式对象,然后绑定给不同的Handler对象使用,以此来控制不同的Handler的日志格式
5,Logger与Handler的级别
1 Logger is also the first to filter the message based on a level — if you set the logger to INFO, and all handlers to DEBUG, you still won't receive DEBUG messages on handlers — they'll be rejected by the logger itself. If you set logger to DEBUG, but all handlers to INFO, you won't receive any DEBUG messages either — because while the logger says "ok, process this", the handlers reject it (DEBUG < INFO). 2 3 4 5 #验证 6 import logging 7 8 9 form=logging.Formatter('%(asctime)s - %(name)s - %(levelname)s -%(module)s: %(message)s', 10 datefmt='%Y-%m-%d %H:%M:%S %p',) 11 12 ch=logging.StreamHandler() 13 14 ch.setFormatter(form) 15 # ch.setLevel(10) 16 ch.setLevel(20) 17 18 l1=logging.getLogger('root') 19 # l1.setLevel(20) 20 l1.setLevel(10) 21 l1.addHandler(ch) 22 23 l1.debug('l1 debug')
7,应用
1 """ 2 logging配置 3 """ 4 5 import os 6 import logging.config 7 8 # 定义三种日志输出格式 开始 9 10 standard_format = '[%(asctime)s][%(threadName)s:%(thread)d][task_id:%(name)s][%(filename)s:%(lineno)d]' \ 11 '[%(levelname)s][%(message)s]' #其中name为getlogger指定的名字 12 13 simple_format = '[%(levelname)s][%(asctime)s][%(filename)s:%(lineno)d]%(message)s' 14 15 id_simple_format = '[%(levelname)s][%(asctime)s] %(message)s' 16 17 # 定义日志输出格式 结束 18 19 logfile_dir = os.path.dirname(os.path.abspath(__file__)) # log文件的目录 20 21 logfile_name = 'all2.log' # log文件名 22 23 # 如果不存在定义的日志目录就创建一个 24 if not os.path.isdir(logfile_dir): 25 os.mkdir(logfile_dir) 26 27 # log文件的全路径 28 logfile_path = os.path.join(logfile_dir, logfile_name) 29 30 # log配置字典 31 LOGGING_DIC = { 32 'version': 1, 33 'disable_existing_loggers': False, 34 'formatters': { 35 'standard': { 36 'format': standard_format 37 }, 38 'simple': { 39 'format': simple_format 40 }, 41 }, 42 'filters': {}, 43 'handlers': { 44 #打印到终端的日志 45 'console': { 46 'level': 'DEBUG', 47 'class': 'logging.StreamHandler', # 打印到屏幕 48 'formatter': 'simple' 49 }, 50 #打印到文件的日志,收集info及以上的日志 51 'default': { 52 'level': 'DEBUG', 53 'class': 'logging.handlers.RotatingFileHandler', # 保存到文件 54 'formatter': 'standard', 55 'filename': logfile_path, # 日志文件 56 'maxBytes': 1024*1024*5, # 日志大小 5M 57 'backupCount': 5, 58 'encoding': 'utf-8', # 日志文件的编码,再也不用担心中文log乱码了 59 }, 60 }, 61 'loggers': { 62 #logging.getLogger(__name__)拿到的logger配置 63 '': { 64 'handlers': ['default', 'console'], # 这里把上面定义的两个handler都加上,即log数据既写入文件又打印到屏幕 65 'level': 'DEBUG', 66 'propagate': True, # 向上(更高level的logger)传递 67 }, 68 }, 69 } 70 71 72 def load_my_logging_cfg(): 73 logging.config.dictConfig(LOGGING_DIC) # 导入上面定义的logging配置 74 logger = logging.getLogger(__name__) # 生成一个log实例 75 logger.info('It works!') # 记录该文件的运行状态 76 77 if __name__ == '__main__': 78 load_my_logging_cfg() 79 复制代码 80 81 复制代码 82 """ 83 MyLogging Test 84 """ 85 86 import time 87 import logging 88 import my_logging # 导入自定义的logging配置 89 90 logger = logging.getLogger(__name__) # 生成logger实例 91 92 93 def demo(): 94 logger.debug("start range... time:{}".format(time.time())) 95 logger.info("中文测试开始。。。") 96 for i in range(10): 97 logger.debug("i:{}".format(i)) 98 time.sleep(0.2) 99 else: 100 logger.debug("over range... time:{}".format(time.time())) 101 logger.info("中文测试结束。。。") 102 103 if __name__ == "__main__": 104 my_logging.load_my_logging_cfg() # 在你程序文件的入口加载自定义logging配置 105 demo() 106 复制代码 107 108 复制代码 109 注意注意注意: 110 111 112 #1、有了上述方式我们的好处是:所有与logging模块有关的配置都写到字典中就可以了,更加清晰,方便管理 113 114 115 #2、我们需要解决的问题是: 116 1、从字典加载配置:logging.config.dictConfig(settings.LOGGING_DIC) 117 118 2、拿到logger对象来产生日志 119 logger对象都是配置到字典的loggers 键对应的子字典中的 120 按照我们对logging模块的理解,要想获取某个东西都是通过名字,也就是key来获取的 121 于是我们要获取不同的logger对象就是 122 logger=logging.getLogger('loggers子字典的key名') 123 124 125 但问题是:如果我们想要不同logger名的logger对象都共用一段配置,那么肯定不能在loggers子字典中定义n个key 126 'loggers': { 127 'l1': { 128 'handlers': ['default', 'console'], # 129 'level': 'DEBUG', 130 'propagate': True, # 向上(更高level的logger)传递 131 }, 132 'l2: { 133 'handlers': ['default', 'console' ], 134 'level': 'DEBUG', 135 'propagate': False, # 向上(更高level的logger)传递 136 }, 137 'l3': { 138 'handlers': ['default', 'console'], # 139 'level': 'DEBUG', 140 'propagate': True, # 向上(更高level的logger)传递 141 }, 142 143 } 144 145 146 #我们的解决方式是,定义一个空的key 147 'loggers': { 148 '': { 149 'handlers': ['default', 'console'], 150 'level': 'DEBUG', 151 'propagate': True, 152 }, 153 154 } 155 156 这样我们再取logger对象时 157 logging.getLogger(__name__),不同的文件__name__不同,这保证了打印日志时标识信息不同,但是拿着该名字去loggers里找key名时却发现找不到,于是默认使用key=''的配置 158 复制代码 159 另外一个django的配置,瞄一眼就可以,跟上面的一样 160 161 复制代码 162 #logging_config.py 163 LOGGING = { 164 'version': 1, 165 'disable_existing_loggers': False, 166 'formatters': { 167 'standard': { 168 'format': '[%(asctime)s][%(threadName)s:%(thread)d][task_id:%(name)s][%(filename)s:%(lineno)d]' 169 '[%(levelname)s][%(message)s]' 170 }, 171 'simple': { 172 'format': '[%(levelname)s][%(asctime)s][%(filename)s:%(lineno)d]%(message)s' 173 }, 174 'collect': { 175 'format': '%(message)s' 176 } 177 }, 178 'filters': { 179 'require_debug_true': { 180 '()': 'django.utils.log.RequireDebugTrue', 181 }, 182 }, 183 'handlers': { 184 #打印到终端的日志 185 'console': { 186 'level': 'DEBUG', 187 'filters': ['require_debug_true'], 188 'class': 'logging.StreamHandler', 189 'formatter': 'simple' 190 }, 191 #打印到文件的日志,收集info及以上的日志 192 'default': { 193 'level': 'INFO', 194 'class': 'logging.handlers.RotatingFileHandler', # 保存到文件,自动切 195 'filename': os.path.join(BASE_LOG_DIR, "xxx_info.log"), # 日志文件 196 'maxBytes': 1024 * 1024 * 5, # 日志大小 5M 197 'backupCount': 3, 198 'formatter': 'standard', 199 'encoding': 'utf-8', 200 }, 201 #打印到文件的日志:收集错误及以上的日志 202 'error': { 203 'level': 'ERROR', 204 'class': 'logging.handlers.RotatingFileHandler', # 保存到文件,自动切 205 'filename': os.path.join(BASE_LOG_DIR, "xxx_err.log"), # 日志文件 206 'maxBytes': 1024 * 1024 * 5, # 日志大小 5M 207 'backupCount': 5, 208 'formatter': 'standard', 209 'encoding': 'utf-8', 210 }, 211 #打印到文件的日志 212 'collect': { 213 'level': 'INFO', 214 'class': 'logging.handlers.RotatingFileHandler', # 保存到文件,自动切 215 'filename': os.path.join(BASE_LOG_DIR, "xxx_collect.log"), 216 'maxBytes': 1024 * 1024 * 5, # 日志大小 5M 217 'backupCount': 5, 218 'formatter': 'collect', 219 'encoding': "utf-8" 220 } 221 }, 222 'loggers': { 223 #logging.getLogger(__name__)拿到的logger配置 224 '': { 225 'handlers': ['default', 'console', 'error'], 226 'level': 'DEBUG', 227 'propagate': True, 228 }, 229 #logging.getLogger('collect')拿到的logger配置 230 'collect': { 231 'handlers': ['console', 'collect'], 232 'level': 'INFO', 233 } 234 }, 235 } 236 237 238 # ----------- 239 # 用法:拿到俩个logger 240 241 logger = logging.getLogger(__name__) #线上正常的日志 242 collect_logger = logging.getLogger("collect") #领导说,需要为领导们单独定制领导们看的日志
8,日志配置字典
1 """ 2 logging配置 3 """ 4 5 import os 6 7 # 1、定义三种日志输出格式,日志中可能用到的格式化串如下 8 # %(name)s Logger的名字 9 # %(levelno)s 数字形式的日志级别 10 # %(levelname)s 文本形式的日志级别 11 # %(pathname)s 调用日志输出函数的模块的完整路径名,可能没有 12 # %(filename)s 调用日志输出函数的模块的文件名 13 # %(module)s 调用日志输出函数的模块名 14 # %(funcName)s 调用日志输出函数的函数名 15 # %(lineno)d 调用日志输出函数的语句所在的代码行 16 # %(created)f 当前时间,用UNIX标准的表示时间的浮 点数表示 17 # %(relativeCreated)d 输出日志信息时的,自Logger创建以 来的毫秒数 18 # %(asctime)s 字符串形式的当前时间。默认格式是 “2003-07-08 16:49:45,896”。逗号后面的是毫秒 19 # %(thread)d 线程ID。可能没有 20 # %(threadName)s 线程名。可能没有 21 # %(process)d 进程ID。可能没有 22 # %(message)s用户输出的消息 23 24 # 2、强调:其中的%(name)s为getlogger时指定的名字 25 standard_format = '[%(asctime)s][%(threadName)s:%(thread)d][task_id:%(name)s][%(filename)s:%(lineno)d]' \ 26 '[%(levelname)s][%(message)s]' 27 28 simple_format = '[%(levelname)s][%(asctime)s][%(filename)s:%(lineno)d]%(message)s' 29 30 test_format = '%(asctime)s] %(message)s' 31 32 # 3、日志配置字典 33 LOGGING_DIC = { 34 'version': 1, 35 'disable_existing_loggers': False, 36 'formatters': { 37 'standard': { 38 'format': standard_format 39 }, 40 'simple': { 41 'format': simple_format 42 }, 43 'test': { 44 'format': test_format 45 }, 46 }, 47 'filters': {}, 48 'handlers': { 49 #打印到终端的日志 50 'console': { 51 'level': 'DEBUG', 52 'class': 'logging.StreamHandler', # 打印到屏幕 53 'formatter': 'simple' 54 }, 55 #打印到文件的日志,收集info及以上的日志 56 'default': { 57 'level': 'DEBUG', 58 'class': 'logging.handlers.RotatingFileHandler', # 保存到文件,日志轮转 59 'formatter': 'standard', 60 # 可以定制日志文件路径 61 # BASE_DIR = os.path.dirname(os.path.abspath(__file__)) # log文件的目录 62 # LOG_PATH = os.path.join(BASE_DIR,'a1.log') 63 'filename': 'a1.log', # 日志文件 64 'maxBytes': 1024*1024*5, # 日志大小 5M 65 'backupCount': 5, 66 'encoding': 'utf-8', # 日志文件的编码,再也不用担心中文log乱码了 67 }, 68 'other': { 69 'level': 'DEBUG', 70 'class': 'logging.FileHandler', # 保存到文件 71 'formatter': 'test', 72 'filename': 'a2.log', 73 'encoding': 'utf-8', 74 }, 75 }, 76 'loggers': { 77 #logging.getLogger(__name__)拿到的logger配置 78 '': { 79 'handlers': ['default', 'console'], # 这里把上面定义的两个handler都加上,即log数据既写入文件又打印到屏幕 80 'level': 'DEBUG', # loggers(第一层日志级别关限制)--->handlers(第二层日志级别关卡限制) 81 'propagate': False, # 默认为True,向上(更高level的logger)传递,通常设置为False即可,否则会一份日志向上层层传递 82 }, 83 '专门的采集': { 84 'handlers': ['other',], 85 'level': 'DEBUG', 86 'propagate': False, 87 }, 88 },
注意:
1 import settings 2 3 # !!!强调!!! 4 # 1、logging是一个包,需要使用其下的config、getLogger,可以如下导入 5 # from logging import config 6 # from logging import getLogger 7 8 # 2、也可以使用如下导入 9 import logging.config # 这样连同logging.getLogger都一起导入了,然后使用前缀logging.config. 10 11 # 3、加载配置 12 logging.config.dictConfig(settings.LOGGING_DIC) 13 14 # 4、输出日志 15 logger1=logging.getLogger('用户交易') 16 logger1.info('egon儿子alex转账3亿冥币') 17 18 # logger2=logging.getLogger('专门的采集') # 名字传入的必须是'专门的采集',与LOGGING_DIC中的配置唯一对应 19 # logger2.debug('专门采集的日志')
日志名字:

日志轮转:
就是设置日志文件的大小,保证超出文件大小时会创建新的文件。但注意的是会把老的文件放到新创立的文件里,这样就会保证新的日志永远在指定的文件夹里。
十一,re模块

一:什么是正则?
正则就是用一些具有特殊含义的符号组合到一起(称为正则表达式)来描述字符或者字符串的方法。或者说:正则就是用来描述一类事物的规则。(在Python中)它内嵌在Python中,并通过 re 模块实现。正则表达式模式被编译成一系列的字节码,然后由用 C 编写的匹配引擎执行。
生活中处处都是正则:
比如我们描述:4条腿
你可能会想到的是四条腿的动物或者桌子,椅子等
继续描述:4条腿,活的
就只剩下四条腿的动物这一类了
二:常用匹配模式(元字符)
http://blog.csdn.net/yufenghyc/article/details/51078107

# =================================匹配模式=================================
#一对一的匹配
# 'hello'.replace(old,new)
# 'hello'.find('pattern')
#正则匹配
import re
#\w与\W
print(re.findall('\w','hello egon 123')) #['h', 'e', 'l', 'l', 'o', 'e', 'g', 'o', 'n', '1', '2', '3']
print(re.findall('\W','hello egon 123')) #[' ', ' ']
#\s与\S
print(re.findall('\s','hello egon 123')) #[' ', ' ', ' ', ' ']
print(re.findall('\S','hello egon 123')) #['h', 'e', 'l', 'l', 'o', 'e', 'g', 'o', 'n', '1', '2', '3']
#\n \t都是空,都可以被\s匹配
print(re.findall('\s','hello \n egon \t 123')) #[' ', '\n', ' ', ' ', '\t', ' ']
#\n与\t
print(re.findall(r'\n','hello egon \n123')) #['\n']
print(re.findall(r'\t','hello egon\t123')) #['\n']
#\d与\D
print(re.findall('\d','hello egon 123')) #['1', '2', '3']
print(re.findall('\D','hello egon 123')) #['h', 'e', 'l', 'l', 'o', ' ', 'e', 'g', 'o', 'n', ' ']
#\A与\Z
print(re.findall('\Ahe','hello egon 123')) #['he'],\A==>^
print(re.findall('123\Z','hello egon 123')) #['he'],\Z==>$
^
指定匹配必须出现在字符串的开头或行的开头。
\A
指定匹配必须出现在字符串的开头(忽略 Multiline 选项)。
$
指定匹配必须出现在以下位置:字符串结尾、字符串结尾的 \n 之前或行的结尾。
\Z
指定匹配必须出现在字符串的结尾或字符串结尾的 \n 之前(忽略 Multiline 选项)。
#^与$
print(re.findall('^h','hello egon 123')) #['h']
print(re.findall('3$','hello egon 123')) #['3']
# 重复匹配:| . | * | ? | .* | .*? | + | {n,m} |
#.
print(re.findall('a.b','a1b')) #['a1b']
print(re.findall('a.b','a1b a*b a b aaab')) #['a1b', 'a*b', 'a b', 'aab']
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']
#?
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']
#+
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*'
#[]
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')) #[]内的^代表的意思是取反,所以结果为['a=b']
print(re.findall('a[a-z]b','a1b a*b a-b a=b aeb')) #[]内的^代表的意思是取反,所以结果为['a=b']
print(re.findall('a[a-zA-Z]b','a1b a*b a-b a=b aeb aEb')) #[]内的^代表的意思是取反,所以结果为['a=b']
#\# 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']
#():分组
print(re.findall('ab+','ababab123')) #['ab', 'ab', 'ab']
print(re.findall('(ab)+123','ababab123')) #['ab'],匹配到末尾的ab123中的ab
print(re.findall('(?:ab)+123','ababab123')) #findall的结果不是匹配的全部内容,而是组内的内容,?:可以让结果为匹配的全部内容
print(re.findall('href="(.*?)"','<a href="http://www.baidu.com">点击</a>'))#['http://www.baidu.com']
print(re.findall('href="(?:.*?)"','<a href="http://www.baidu.com">点击</a>'))#['href="http://www.baidu.com"']
#|
print(re.findall('compan(?:y|ies)','Too many companies have gone bankrupt, and the next one is my company'))
# ===========================re模块提供的方法介绍===========================
import re
#1
print(re.findall('e','alex make love') ) #['e', 'e', 'e'],返回所有满足匹配条件的结果,放在列表里
#2
print(re.search('e','alex make love').group()) #e,只到找到第一个匹配然后返回一个包含匹配信息的对象,该对象可以通过调用group()方法得到匹配的字符串,如果字符串没有匹配,则返回None。
#3
print(re.match('e','alex make love')) #None,同search,不过在字符串开始处进行匹配,完全可以用search+^代替match
#4
print(re.split('[ab]','abcd')) #['', '', 'cd'],先按'a'分割得到''和'bcd',再对''和'bcd'分别按'b'分割
#5
print('===>',re.sub('a','A','alex make love')) #===> Alex mAke love,不指定n,默认替换所有
print('===>',re.sub('a','A','alex make love',1)) #===> Alex make love
print('===>',re.sub('a','A','alex make love',2)) #===> Alex mAke love
print('===>',re.sub('^(\w+)(.*?\s)(\w+)(.*?\s)(\w+)(.*?)$',r'\5\2\3\4\1','alex make love')) #===> love make alex
print('===>',re.subn('a','A','alex make love')) #===> ('Alex mAke love', 2),结果带有总共替换的个数
#6
obj=re.compile('\d{2}')
print(obj.search('abc123eeee').group()) #12
print(obj.findall('abc123eeee')) #['12'],重用了obj
补充一#补充二
import re
#使用|,先匹配的先生效,|左边是匹配小数,而findall最终结果是查看分组,所有即使匹配成功小数也不会存入结果
#而不是小数时,就去匹配(-?\d+),匹配到的自然就是,非小数的数,在此处即整数
#
print(re.findall(r"-?\d+\.\d*|(-?\d+)","1-2*(60+(-40.35/5)-(-4*3))")) #找出所有整数['1', '-2', '60', '', '5', '-4', '3']
#找到所有数字:
print(re.findall('\D?(\-?\d+\.?\d*)',"1-2*(60+(-40.35/5)-(-4*3))")) # ['1','2','60','-40.35','5','-4','3']
#计算器作业参考:http://www.cnblogs.com/wupeiqi/articles/4949995.html
expression='1-2*((60+2*(-3-40.0/5)*(9-2*5/3+7/3*99/4*2998+10*568/14))-(-4*3)/(16-3*2))'
content=re.search('\(([\-\+\*\/]*\d+\.?\d*)+\)',expression).group() #(-3-40.0/5)
search与findall
View Code作业:
View Code
补充:
推荐阅读:
https://www.cnblogs.com/linhaifeng/articles/13432794.html
正则表达式中(?:pattern)、(?=pattern)、(?!pattern)、(?<=pattern)和(?<!pattern)
下述表达式都是断言,不占用宽度
前面有,正向后发(?<=exp),放前面;
后面有,正向先行(?=exp),放后面;
前面无,反向后发(?<!exp),放前面;
后面无,反向先行(?!exp),放后面。
例如
re.findall("egon(?=100|N)(?=N)N123","egonN123") # ['egonN123']
# 位置: 0 1 2 3 4 5 6 7
# 字符串:e g o n N 1 2 3
# 分析:
# 步骤1、正则表达式egon匹配到了字符串的位置3
然后连续进行两次断言匹配
# 步骤2、(?=100|N)从位置3作为起始匹配位置4的字符是否100或者N
# 步骤3、2成功后,继续匹配(?=N),因为?=patter不会吃字符,所以此时会重新回到步骤1所在位置3,然后继续匹配,匹配成功
# 步骤4、从位置3开始匹配N123
# 思考下述输出结果,为何会不同???:
re.findall("egon(?=100|N)(?=N)N123","egonN123")
re.findall("egon(?=100|N)(?=N)123","egonN123")
介绍
(pattern) : 匹配 pattern 并获取这一匹配,所获取的匹配可以从产生的 Matches 集合得到。
(?:pattern) :匹配 pattern 但不获取匹配结果,也就是说这是一个非获取匹配,不进行存储供以后使用。
(?=pattern) :正向预查,在任何匹配 pattern 的字符串开始处匹配查找字符串。这是一个非获取匹配,也就是说,该匹配不需要获取供以后使用。预查不消耗字符,也就是说,在一个匹配发生后,在最后一次匹配之后立即开始下一次匹配的搜索,而不是从包含预查的字符之后开始。
共同点
(?:pattern) 与 (?=pattern)都匹配pattern,但不会把pattern结果放到Matches的集合中,即Matcher.group()不会匹配到(?;pattern)与(?=pattern)
区别
(?:pattern)匹配得到的结果包含pattern,(?=pattern)则不包含。如:对字符串:"industry abc"的匹配结果: industr(?:y|ies) ---> "industry" industr(?=y|ies) ---> "industr"
是否消耗字符
(?:pattern)消耗字符,下一字符匹配会从已匹配后的位置开始。(?=pattern)不消耗字符,下一字符匹配会从预查之前的位置开始。
即后者只预查,不移动匹配指针。如:

posted on 2024-02-14 02:46 我才是最帅的那个男人 阅读(21) 评论(0) 收藏 举报


浙公网安备 33010602011771号