Python之模块
Python之模块
时间模块:
import time
time模块有三种方式来表示时间:时间戳,元组,格式化的时间字符串。
(1)时间戳(给计算机看的):timestamp通常来说,时间戳表示的是从1970年1月1日00:00:00开始按秒计算的偏移量,运行type(time.time()),返回的是float类型。
(2)格式化的时间字符串(给人看的):Format String "1988-03-16"
(3)元组(结构化时间:可以操作时间的):struct_time 元组共有9个元素(年、月、日、时、分、秒、一年中第几周、一年中第几天)
1 # <1> 时间戳 2 3 >>> import time 4 >>> time.time() #--------------返回当前时间的时间戳 5 6 1493136727.099066 7 8 # <2> 时间字符串 9 10 >>> time.strftime("%Y-%m-%d %X") 11 '2017-04-26 00:32:18' 12 13 # <3> 时间元组 14 15 >>> time.localtime() 16 time.struct_time(tm_year=2017, tm_mon=4, tm_mday=26, 17 tm_hour=0, tm_min=32, tm_sec=42, tm_wday=2, 18 tm_yday=116, tm_isdst=0)
小结:时间戳是计算机能够识别的时间;时间字符串是人能够看懂的时间;元组则是用来操作时间的
1 #一 时间戳<---->结构化时间: localtime/gmtime mktime 2 import time 3 time.localtime(3600*24) 4 time.gmtime(3600*24) 5 6 time.mktime(time.localtime()) 7 8 9 ##字符串时间<---->结构化时间: strftime/strptime 10 11 time.strftime("%Y-%m-%d %X", time.localtime()) 12 time.strptime("2017-03-16","%Y-%m-%d")
>>> time.asctime(time.localtime(312343423)) 'Sun Nov 25 10:03:43 1979' >>> time.ctime(312343423) 'Sun Nov 25 10:03:43 1979' 1 #--------------------------其他方法 2 # sleep(secs) 3 # 线程推迟指定的时间运行,单位为秒。
random模块:
random随机模块
1 import random 2 random.random() # 大于0且小于1之间的小数 3 0.7664338663654585 4 5 random.randint(1,5) # 大于等于1且小于等于5之间的整数 6 7 random.randrange(1,3) # 大于等于1且小于3之间的整数 8 9 random.choice([1,'23',[4,5]]) # #1或者23或者[4,5] 10 11 random.sample([1,'23',[4,5]],2) # #列表元素任意2个组合 12 [[4, 5], '23'] 13 14 random.uniform(1,3) #大于1小于3的小数 15 1.6270147180533838 16 17 item=[1,3,5,7,9] 18 random.shuffle(item) # 打乱次序 19 item 20 [5, 1, 3, 7, 9] 21 random.shuffle(item) 22 item 23 [5, 9, 7, 1, 3]
练习:生成验证码
1 import random 2 3 def v_code(): 4 5 code = '' 6 for i in range(5): 7 8 num=random.randint(0,9) 9 alf=chr(random.randint(65,90)) 10 add=random.choice([num,alf]) 11 code="".join([code,str(add)]) 12 13 return code 14 15 print(v_code())
1 import random 2 3 4 #print(random.random()) 5 6 #print(random.randint(1,4)) #[1,4] 7 #print(random.randrange(1,3)) #[1,3) 8 9 # print(random.choice([11,26,3,4])) 10 # print(random.sample([11,26,3,4],2)) 11 12 #print(random.uniform(1,3)) 13 14 # item=[1,23,33] 15 # 16 # random.shuffle(item) 17 # print(item) 18 19 # a-z A-Z 20 21 22 def validate(): 23 24 s="" 25 for i in range(5): 26 rNum=random.randint(0,9) 27 r_alph=chr(random.randint(65,90)) 28 29 ret=random.choice([str(rNum),r_alph]) 30 s+=ret 31 32 return s 33 34 print(validate())
hashiliib模块:
Python的hashlib提供了常见的摘要算法,如MD5,SHA1等等。
什么是摘要算法呢?摘要算法又称哈希算法、散列算法。它通过一个函数,把任意长度的数据转换为一个长度固定的数据串(通常用16进制的字符串表示)。
摘要算法就是通过摘要函数f()对任意长度的数据data计算出固定长度的摘要digest,目的是为了发现原始数据是否被人篡改过。
摘要算法之所以能指出数据是否被篡改过,就是因为摘要函数是一个单向函数,计算f(data)很容易,但通过digest反推data却非常困难。
而且,对原始数据做一个bit的修改,都会导致计算出的摘要完全不同。
我们以常见的摘要算法MD5为例,计算出一个字符串的MD5值:
import hashlib md5 = hashlib.md5() md5.update('how to use md5 in python hashlib?') print md5.hexdigest() 计算结果如下: d26a53750bc40b38b65a520292f69306
如果数据量很大,可以分块多次调用update(),最后计算的结果是一样的:
md5 = hashlib.md5() md5.update('how to use md5 in ') md5.update('python hashlib?') print md5.hexdigest()
MD5是最常见的摘要算法,速度很快,生成结果是固定的128 bit字节,通常用一个32位的16进制字符串表示。另一种常见的摘要算法是SHA1,调用SHA1和调用MD5完全类似:
import hashlib sha1 = hashlib.sha1() sha1.update('how to use sha1 in ') sha1.update('python hashlib?') print sha1.hexdigest()
SHA1的结果是160 bit字节,通常用一个40位的16进制字符串表示。比SHA1更安全的算法是SHA256和SHA512,不过越安全的算法越慢,而且摘要长度更长。
摘要算法应用:
任何允许用户登录的网站都会存储用户登录的用户名和口令。如何存储用户名和口令呢?方法是存到数据库表中:
name | password --------+---------- michael | 123456 bob | abc999 alice | alice2008
如果以明文保存用户口令,如果数据库泄露,所有用户的口令就落入黑客的手里。此外,网站运维人员是可以访问数据库的,也就是能获取到所有用户的口令。正确的保存口令的方式是不存储用户的明文口令,而是存储用户口令的摘要,比如MD5:
username | password ---------+--------------------------------- michael | e10adc3949ba59abbe56e057f20f883e bob | 878ef96e86145580c38c87f0410ad153 alice | 99b1c2188db85afee403b1536010c2c9
考虑这么个情况,很多用户喜欢用123456,888888,password这些简单的口令,于是,黑客可以事先计算出这些常用口令的MD5值,得到一个反推表:
'e10adc3949ba59abbe56e057f20f883e': '123456' '21218cca77804d2ba1922c33e0151105': '888888' '5f4dcc3b5aa765d61d8327deb882cf99': 'password'
这样,无需破解,只需要对比数据库的MD5,黑客就获得了使用常用口令的用户账号。
对于用户来讲,当然不要使用过于简单的口令。但是,我们能否在程序设计上对简单口令加强保护呢?
由于常用口令的MD5值很容易被计算出来,所以,要确保存储的用户口令不是那些已经被计算出来的常用口令的MD5,这一方法通过对原始口令加一个复杂字符串来实现,俗称“加盐”:
hashlib.md5("salt".encode("utf8"))
经过Salt处理的MD5口令,只要Salt不被黑客知道,即使用户输入简单口令,也很难通过MD5反推明文口令。
但是如果有两个用户都使用了相同的简单口令比如123456,在数据库中,将存储两条相同的MD5值,这说明这两个用户的口令是一样的。有没有办法让使用相同口令的用户存储不同的MD5呢?
如果假定用户无法修改登录名,就可以通过把登录名作为Salt的一部分来计算MD5,从而实现相同口令的用户也存储不同的MD5。
摘要算法在很多地方都有广泛的应用。要注意摘要算法不是加密算法,不能用于加密(因为无法通过摘要反推明文),只能用于防篡改,但是它的单向计算特性决定了可以在不存储明文口令的情况下验证用户口令。
练习:
import hashlib m=hashlib.md5() m.update("alex".encode("utf8")) #534b44a19bf18d20b71ecc4eb77c572f print(m.hexdigest()) m.update("alex".encode("utf8")) #alexalex print(m.hexdigest()) n=hashlib.md5("salt".encode("utf8")) #加盐 n.update(b"alexalex") print(n.hexdigest()) # m=hashlib.sha1()
os模块:
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 获取系统环境变量 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的大小 '''
注意:
os.stat('path/filename') 获取文件/目录信息
stat 结构: st_mode: inode 保护模式 st_ino: inode 节点号。 st_dev: inode 驻留的设备。 st_nlink: inode 的链接数。 st_uid: 所有者的用户ID。 st_gid: 所有者的组ID。 st_size: 普通文件以字节为单位的大小;包含等待某些特殊文件的数据。 st_atime: 上次访问的时间。 st_mtime: 最后一次修改的时间。 st_ctime: 由操作系统报告的"ctime"。在某些系统上(如Unix)是最新的元数据更改的时间,在其它系统上(如Windows)是创建时间(详细信息参见平台的文档)。
练习:
import os # print(os.getcwd()) # f=open("test.txt","w") # os.chdir(r"C:\Users\Administrator\PycharmProjects\py_fullstack_s4\day32") # cd # f=open("test2.txt","w") # print(os.getcwd()) #os.makedirs("aaaaa/bbb") #os.removedirs("aaaaa/bbb") #print(os.listdir(r"C:\Users\Administrator\PycharmProjects\py_fullstack_s4\day33")) # print(os.stat(r"C:\Users\Administrator\PycharmProjects\py_fullstack_s4\day33\test.txt")) # ''' # os.stat_result(st_mode=33206, st_ino=10133099161702379, st_dev=3233102476, st_nlink=1, st_uid=0, st_gid=0, st_size=0, st_atime=1493176560, st_mtime=1493176614, st_ctime=1493176560) # # ''' # "yuan"+os.sep+"image" #print(os.name) #print(os.system("dir")) # abs=os.path.abspath("test.txt") # print(os.path.basename(abs)) # print(os.path.dirname(abs)) s1=r"C:\Users\Administrator\PycharmProjects" s2=r"py_fullstack_s4\day33" #print(s1+os.sep+s2) ret=os.path.join(s1,s2) # 推荐方式 print(ret)
sys模块:
sys.argv 命令行参数List,第一个元素是程序本身路径
sys.exit(n) 退出程序,正常退出时exit(0)
sys.version 获取Python解释程序的版本信息
sys.maxint 最大的Int值
sys.path 返回模块的搜索路径,初始化时使用PYTHONPATH环境变量的值
sys.platform 返回操作系统平台名称
回到顶部
logging日志模块:
函数式简单配置
import logging logging.debug('debug message') logging.info('info message') logging.warning('warning message') logging.error('error message') logging.critical('critical message')
默认情况下Python的logging模块将日志打印到了标准输出中,且只显示了大于等于WARNING级别的日志,这说明默认的日志级别设置为
WARNING(日志级别等级CRITICAL > ERROR > WARNING > INFO > DEBUG),默认的日志格式为日志级别:Logger名称:用户输出消息。
灵活配置日志级别,日志格式,输出位置:
import logging logging.basicConfig(level=logging.DEBUG, format='%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s', datefmt='%a, %d %b %Y %H:%M:%S', filename='/tmp/test.log', filemode='w') logging.debug('debug message') logging.info('info message') logging.warning('warning message') logging.error('error message') logging.critical('critical message')
配置参数:
1 logging.basicConfig()函数中可通过具体参数来更改logging模块默认行为,可用参数有: 2 3 filename:用指定的文件名创建FiledHandler,这样日志会被存储在指定的文件中。 4 filemode:文件打开方式,在指定了filename时使用这个参数,默认值为“a”还可指定为“w”。 5 format:指定handler使用的日志显示格式。 6 datefmt:指定日期时间格式。 7 level:设置rootlogger(后边会讲解具体概念)的日志级别 8 stream:用指定的stream创建StreamHandler。可以指定输出到sys.stderr,sys.stdout或者文件(f=open(‘test.log’,’w’)),默认为sys.stderr。若同时列出了filename和stream两个参数,则stream参数会被忽略。 9 10 format参数中可能用到的格式化串: 11 %(name)s Logger的名字 12 %(levelno)s 数字形式的日志级别 13 %(levelname)s 文本形式的日志级别 14 %(pathname)s 调用日志输出函数的模块的完整路径名,可能没有 15 %(filename)s 调用日志输出函数的模块的文件名 16 %(module)s 调用日志输出函数的模块名 17 %(funcName)s 调用日志输出函数的函数名 18 %(lineno)d 调用日志输出函数的语句所在的代码行 19 %(created)f 当前时间,用UNIX标准的表示时间的浮 点数表示 20 %(relativeCreated)d 输出日志信息时的,自Logger创建以 来的毫秒数 21 %(asctime)s 字符串形式的当前时间。默认格式是 “2003-07-08 16:49:45,896”。逗号后面的是毫秒 22 %(thread)d 线程ID。可能没有 23 %(threadName)s 线程名。可能没有 24 %(process)d 进程ID。可能没有 25 %(message)s用户输出的消息
logger对象配置:
import logging logger = logging.getLogger() # 创建一个handler,用于写入日志文件 fh = logging.FileHandler('test.log') # 再创建一个handler,用于输出到控制台 ch = logging.StreamHandler() formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') fh.setFormatter(formatter) ch.setFormatter(formatter) logger.addHandler(fh) #logger对象可以添加多个fh和ch对象 logger.addHandler(ch) logger.debug('logger debug message') logger.info('logger info message') logger.warning('logger warning message') logger.error('logger error message') logger.critical('logger critical message')
logging库提供了多个组件:Logger、Handler、Filter、Formatter。Logger对象提供应用程序可直接使用的接口,Handler发送日志到适当的目的地,Filter提供了过滤日志信息的方法,Formatter指定日志显示格式。另外,可以通过:logger.setLevel(logging.Debug)设置级别,当然,也可以通过
fh.setLevel(logging.Debug)单对文件流设置某个级别。
1 import logging 2 3 import logging 4 5 # debug info warning(默认) error critical 6 7 #1 congfig函数 8 9 # logging.basicConfig(level=logging.DEBUG, 10 # format="%(asctime)s [%(lineno)s] %(message)s", 11 # datefmt="%Y-%m-%d %H:%M:%S", 12 # filename="logger", 13 # filemode="a" 14 # ) 15 16 # logging.debug('debug message') 17 # num=1000 18 # logging.info('cost %s'%num) 19 20 # logging.warning('warning messagegfdsgsdfg') # 21 # 22 # logging.error('error message') 23 # 24 # logging.critical('critical message') 25 26 27 #配置两种方式: 1 congfig 2 logger 28 29 # 2 logger对象 30 31 def get_logger(): 32 33 logger=logging.getLogger() 34 35 fh=logging.FileHandler("logger2") 36 37 sh=logging.StreamHandler() 38 39 logger.setLevel(logging.DEBUG) #设定输出等级 40 41 fm=logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s") 42 43 logger.addHandler(fh) 44 45 logger.addHandler(sh) 46 47 fh.setFormatter(fm) 48 sh.setFormatter(fm) 49 50 return logger 51 52 Logger=get_logger() 53 54 Logger.debug('logger debug message') 55 Logger.info('logger info message') 56 Logger.warning('logger warning message') 57 Logger.error('logger error message') 58 Logger.critical('logger critical message')
*****json序列化模块*****:
dumps # 将字典d转为json字符串---序列化 ,那倒是的unicode的数据。
loads #将json字符串反序列化成之间的类型
之前我们学习过用eval内置方法可以将一个字符串转成python对象,不过,eval方法是有局限性的,对于普通的数据类型,json.loads和eval都能用,但遇到特殊类型的时候,eval就不管用了,所以eval的重点还是通常用来执行一个字符串表达式,并返回表达式的值。
1 #---转换类型 2 3 d={"name":"yuan"} 4 5 s=str(d) 6 7 print(type(s)) 8 9 d2=eval(s) 10 11 print(d2[1]) 12 13 with open("test") as f: 14 15 for i in f : 16 17 if type(eval(i.strip()))==dict: 18 print(eval(i.strip())[1]) 19 20 # 计算 21 22 print(eval("12*7+5-3"))
什么是序列化?
我们把对象(变量)从内存中变成可存储或传输的过程称之为序列化,在Python中叫pickling,在其他语言中也被称之为serialization,marshalling,flattening等等,都是一个意思。序列化之后,就可以把序列化后的内容写入磁盘,或者通过网络传输到别的机器上。反过来,把变量内容从序列化的对象重新读到内存里称之为反序列化,即unpickling。
json模块:
如果我们要在不同的编程语言之间传递对象,就必须把对象序列化为标准格式,比如XML,但更好的方法是序列化为JSON,因为JSON表示出来就是一个字符串,可以被所有语言读取,也可以方便地存储到磁盘或者通过网络传输。JSON不仅是标准格式,并且比XML更快,而且可以直接在Web页面中读取,非常方便。
JSON表示的对象就是标准的JavaScript语言的对象一个子集,JSON和Python内置的数据类型对应如下:
1 import json 2 i=10 3 s='hello' 4 t=(1,4,6) 5 l=[3,5,7] 6 d={'name':"yuan"} 7 8 json_str1=json.dumps(i) 9 json_str2=json.dumps(s) 10 json_str3=json.dumps(t) 11 json_str4=json.dumps(l) 12 json_str5=json.dumps(d) 13 14 print(json_str1) #'10' 15 print(json_str2) #'"hello"' 16 print(json_str3) #'[1, 4, 6]' 17 print(json_str4) #'[3, 5, 7]' 18 print(json_str5) #'{"name": "yuan"}'
python在文本中的使用:
1 #----------------------------序列化 2 import json 3 4 dic={'name':'alvin','age':23,'sex':'male'} 5 print(type(dic))#<class 'dict'> 6 7 data=json.dumps(dic) 8 print("type",type(data))#<class 'str'> 9 print("data",data) 10 11 12 f=open('序列化对象','w') 13 f.write(data) #-------------------等价于json.dump(dic,f) 14 f.close() 15 16 17 #-----------------------------反序列化<br> 18 import json 19 f=open('序列化对象') 20 new_data=json.loads(f.read())# 等价于data=json.load(f) 21 22 print(type(new_data))
pickle序列化模块:
pickle是无法读的。无法读取内容。
1 ##----------------------------序列化 2 import pickle 3 4 dic={'name':'alvin','age':23,'sex':'male'} 5 6 print(type(dic))#<class 'dict'> 7 8 j=pickle.dumps(dic) 9 print(type(j))#<class 'bytes'> 10 11 12 f=open('序列化对象_pickle','wb')#注意是w是写入str,wb是写入bytes,j是'bytes' 13 f.write(j) #-------------------等价于pickle.dump(dic,f) 14 15 f.close() 16 #-------------------------反序列化 17 import pickle 18 f=open('序列化对象_pickle','rb') 19 20 data=pickle.loads(f.read())# 等价于data=pickle.load(f) 21 22 print(data['age'])
shelve序列化模块:
shelve模块比pickle模块简单,只有一个open函数,返回类似字典的对象,可读可写;key必须为字符串,而值可以是python所支持的数据类型
1 import shelve 2 3 f = shelve.open(r'shelve.txt') 4 5 # f['stu1_info']={'name':'alex','age':'18'} 6 # f['stu2_info']={'name':'alvin','age':'20'} 7 # f['school_info']={'website':'oldboyedu.com','city':'beijing'} 8 # 9 # 10 # f.close() 11 12 print(f.get('stu_info')['age'])
练习:
1 # d={"河北":["廊坊","保定"],"湖南":["长沙","韶山"]} 2 # 3 # s=str(d) 4 # with open("data","w") as f: 5 # f.write(s) 6 7 # with open("data") as f2: 8 # s2=f2.read() 9 # d2=eval(s2) 10 # 11 # print(d2["河北"]) # '{"河北":["廊坊","保定"],"湖南":["长沙","韶山"]}' 12 13 # print(eval("12+34*34")) 14 15 import json 16 17 18 import json 19 20 21 # i=10 22 # s='hello' 23 # t=(1,4,6) 24 # l=[3,5,7] 25 # d={'name':"yuan"} 26 # 27 # json_str1=json.dumps(i) 28 # json_str2=json.dumps(s) 29 # json_str3=json.dumps(t) 30 # json_str4=json.dumps(l) 31 # json_str5=json.dumps(d) 32 # 33 # print(json_str1) #'10' 34 # print(json_str2) #'"hello"' 35 # print(json_str3) #'[1, 4, 6]' 36 # print(json_str4) #'[3, 5, 7]' 37 # print(json_str5) #'{"name": "yuan"}' 38 39 40 41 # # d={"河北":["廊坊","保定"],"湖南":["长沙","韶山"]} 42 # 43 # d={'name':"egon"} 44 # 45 # # s=json.dumps(d) # 将字典d转为json字符串---序列化 ,那倒是的unicode的数据 46 # # 47 # # print(type(s)) 48 # # print(s) 49 # # 50 # # 51 # # f=open("new",'w') 52 # # 53 # # f.write(s) 54 # # 55 # # f.close() 56 # 57 # # -------------- dump方式 58 # 59 # # f=open("new2",'w') 60 # # json.dump(d,f)#---------1 转成json字符串 2 将json字符串写入f里 61 # # 62 # # f.close() 63 # 64 # 65 # #-----------------反序列化 66 # 67 # # f=open("new") 68 # # 69 # # data=f.read() 70 # # 71 # # data2=json.loads(data) 72 # # 73 # # print(data2["name"]) 74 75 76 #------练习 77 78 # f=open("new3") 79 # data=f.read() 80 # 81 # ret=json.loads(data) 82 # # ret=[123] 83 # print(type(ret[0])) 84 85 86 87 #----------------------------------pickle-------------------- 88 89 90 import pickle 91 92 93 import datetime 94 95 t=datetime.datetime.now() 96 97 98 # d={"data":t} 99 100 # json.dump(d,open("new4","w")) 101 102 #d={"name":"alvin"} 103 104 # s=pickle.dumps(d) 105 # print(s) 106 # print(type(s)) 107 # 108 # f=open('new5',"wb") 109 # 110 # f.write(s) 111 # f.close() 112 113 114 # f=open("new5","rb") 115 # 116 # data=pickle.loads(f.read()) 117 # 118 # print(data)
******re模块******:
就其本质而言,正则表达式(或 RE)是一种小型的、高度专业化的编程语言,(在Python中)它内嵌在Python中,并通过 re 模块实现。正则表达式模式被编译成一系列的字节码,然后由用 C 编写的匹配引擎执行。
字符匹配(普通字符,元字符):
1 普通字符:大多数字符和字母都会和自身匹配
>>> re.findall('alvin','yuanaleSxalexwupeiqi')
['alvin']
2 元字符:. ^ $ * + ? { } [ ] | ( ) \
元字符:
. ^ $
1 import re 2 3 ret1=re.findall('李.','李爽\nalex\n李四\negon\nalvin\n李二') 4 5 ret2=re.findall('^李.','李爽\nalex\n李四\negon\nalvin\n李二') 6 7 ret3=re.findall('李.$','李爽\nalex\n李四\negon\nalvin\n李二')
* + ? { }
1 import re 2 3 ret1=re.findall('李.*','李杰\nalex\n李莲英\negon\nalvin\n李二棍子') 4 ret2=re.findall('李.+','李杰\nalex\n李莲英\negon\nalvin\n李二棍子') 5 6 ret3=re.findall('(李.{1,2})\n','李杰\nalex\n李莲英\negon\nalvin\n李二棍子') # 设定优先级的原因 7 8 # 匹配一个数字包括整型和浮点型 9 ret4=re.findall('\d+\.?\d*','12.45,34,0.05,109') 10 11 print(ret4)
注意:前面的*,+,?等都是贪婪匹配,也就是尽可能匹配,后面加?号使其变成惰性匹配
ret=re.findall('131\d+?','1312312312') print(ret) ['1312']
转义符 \
1、反斜杠后边跟元字符去除特殊功能,比如\.
2、反斜杠后边跟普通字符实现特殊功能,比如\d
1 \d 匹配任何十进制数; 它相当于类 [0-9]。 2 \D 匹配任何非数字字符; 它相当于类 [^0-9]。 3 \s 匹配任何空白字符; 它相当于类 [ \t\n\r\f\v]。 4 \S 匹配任何非空白字符; 它相当于类 [^ \t\n\r\f\v]。 5 \w 匹配任何字母数字字符; 它相当于类 [a-zA-Z0-9_]。 6 \W 匹配任何非字母数字字符; 它相当于类 [^a-zA-Z0-9_] 7 \b 匹配一个特殊字符边界,比如空格 ,&,#等
让我们看一下\b的应用:
ret=re.findall(r'I\b','I am LIST') print(ret)#['I']
接下来我们试着匹配下“abc\le”中的‘c\l’:
1 import re 2 3 ret=re.findall('c\l','abc\le') 4 print(ret)#[] 5 6 ret=re.findall('c\\l','abc\le') 7 print(ret)#[] 8 9 ret=re.findall('c\\\\l','abc\le') 10 print(ret)#[] 11 12 ret=re.findall(r'c\\l','abc\le') 13 print(ret)#[] 14 15 16 # \b是特殊符号所以,'abc\be'前面需要加r 17 ret=re.findall(r'c\\b',r'abc\be') 18 print(ret)#[]
分组 ()
m = re.findall(r'(ad)+', 'add') print(m) ret=re.search('(?P<id>\d{2})/(?P<name>\w{3})','23/com') print(ret.group())#23/com print(ret.group('id'))#23
元字符之|
ret=re.search('(ab)|\d','rabhdg8sd') print(ret.group())#ab
字符集[]
1 #--------------------------------------------字符集[] 2 ret=re.findall('a[bc]d','acd') 3 print(ret)#['acd'] 4 5 ret=re.findall('[a-z]','acd') 6 print(ret)#['a', 'c', 'd'] 7 8 ret=re.findall('[.*+]','a.cd+') 9 print(ret)#['.', '+'] 10 11 #在字符集里有功能的符号: - ^ \ 12 13 ret=re.findall('[1-9]','45dha3') 14 print(ret)#['4', '5', '3'] 15 16 ret=re.findall('[^ab]','45bdha3') 17 print(ret)#['4', '5', 'd', 'h', '3'] 18 19 ret=re.findall('[\d]','45bdha3') 20 print(ret)#['4', '5', '3']
贪婪匹配
贪婪匹配:在满足匹配时,匹配尽可能长的字符串,默认情况下,采用贪婪匹配
1 string pattern1 = @"a.*c"; // greedy match 2 Regex regex = new Regex(pattern1); 3 regex.Match("abcabc"); // return "abcabc" 4 非贪婪匹配:在满足匹配时,匹配尽可能短的字符串,使用?来表示非贪婪匹配 5 6 string pattern1 = @"a.*?c"; // non-greedy match 7 Regex regex = new Regex(pattern1); 8 regex.Match("abcabc"); // return "abc"
几个常用的非贪婪匹配Pattern
*? 重复任意次,但尽可能少重复 +? 重复1次或更多次,但尽可能少重复 ?? 重复0次或1次,但尽可能少重复 {n,m}? 重复n到m次,但尽可能少重复 {n,}? 重复n次以上,但尽可能少重复
.*?的用法:
-------------------------------- . 是任意字符 * 是取 0 至 无限长度 ? 是非贪婪模式。 何在一起就是 取尽量少的任意字符,一般不会这么单独写,他大多用在: .*?x 就是取前面任意长度的字符,直到一个x出现
re模块下的常用方法
1 import re 2 3 re.findall('a','alvin yuan') #返回所有满足匹配条件的结果,放在列表里 4 5 re.search('a','alvin yuan').group() 6 7 #函数会在字符串内查找模式匹配,只到找到第一个匹配然后返回一个包含匹配信息的对象,该对象可以 8 # 通过调用group()方法得到匹配的字符串,如果字符串没有匹配,则返回None。 9 10 11 12 re.match('a','abc').group() #同search,不过尽在字符串开始处进行匹配 13 14 15 ret=re.split('[ab]','abcd') #先按'a'分割得到''和'bcd',在对''和'bcd'分别按'b'分割 16 17 print(ret)#['', '', 'cd'] 18 19 20 ret=re.sub('\d','abc','alvin5yuan6',1) 21 22 ret=re.subn('\d','abc','alvin5yuan6') 23 24 25 obj=re.compile('\d{3}') 26 ret=obj.search('abc123eeee') 27 print(ret.group())#123 28 29 30 import re 31 ret=re.finditer('\d','ds3sy4784a') 32 print(ret) #<callable_iterator object at 0x10195f940> 33 34 print(next(ret).group()) 35 print(next(ret).group())
注意:
1 findall的优先级查询:
1 import re 2 3 ret=re.findall('www.(baidu|oldboy).com','www.oldboy.com') 4 print(ret)#['oldboy'] 这是因为findall会优先把匹配结果组里内容返回,如果想要匹配结果,取消权限即可 5 6 ret=re.findall('www.(?:baidu|oldboy).com','www.oldboy.com') 7 print(ret)#['www.oldboy.com']
2 split的优先级查询
ret=re.split("\d+","yuan2egon56alex") print(ret) ret=re.split("(\d+)","yuan2egon56alex") print(ret)
练习
1、匹配标签
1 import re 2 3 print(re.findall("<(?P<tag_name>\w+)>\w+</(?P=tag_name)>","<h1>hello</h1>")) 4 print(re.search("<(?P<tag_name>\w+)>\w+</(?P=tag_name)>","<h1>hello</h1>")) 5 print(re.search(r"<(\w+)>\w+</\1>","<h1>hello</h1>"))
2、匹配整数
1 #匹配出所有的整数 2 import re 3 4 #ret=re.findall(r"\d+{0}]","1-2*(60+(-40.35/5)-(-4*3))") 5 ret=re.findall(r"-?\d+\.\d*|(-?\d+)","1-2*(60+(-40.35/5)-(-4*3))") 6 ret.remove("") 7 8 print(ret)
3、数字匹配
1 1、 匹配一段文本中的每行的邮箱 2 3 2、 匹配一段文本中的每行的时间字符串,比如:‘1990-07-12’; 4 5 分别取出1年的12个月(^(0?[1-9]|1[0-2])$)、 6 一个月的31天:^((0?[1-9])|((1|2)[0-9])|30|31)$ 7 8 3、 匹配一段文本中所有的身份证数字。 9 10 4、 匹配qq号。(腾讯QQ号从10000开始) [1,9][0,9]{4,} 11 12 5、 匹配一个浮点数。 ^(-?\d+)(\.\d+)?$ 或者 -?\d+\.?\d* 13 14 6、 匹配汉字。 ^[\u4e00-\u9fa5]{0,}$ 15 16 7、 匹配出所有整数
4、爬虫练习
1 import requests 2 3 import re 4 import json 5 6 def getPage(url): 7 8 response=requests.get(url) 9 return response.text 10 11 def parsePage(s): 12 13 com=re.compile('<div class="item">.*?<div class="pic">.*?<em .*?>(?P<id>\d+).*?<span class="title">(?P<title>.*?)</span>' 14 '.*?<span class="rating_num" .*?>(?P<rating_num>.*?)</span>.*?<span>(?P<comment_num>.*?)评价</span>',re.S) 15 16 ret=com.finditer(s) 17 for i in ret: 18 yield { 19 "id":i.group("id"), 20 "title":i.group("title"), 21 "rating_num":i.group("rating_num"), 22 "comment_num":i.group("comment_num"), 23 } 24 25 def main(num): 26 27 url='https://movie.douban.com/top250?start=%s&filter='%num 28 response_html=getPage(url) 29 ret=parsePage(response_html) 30 print(ret) 31 f=open("move_info7","a",encoding="utf8") 32 33 for obj in ret: 34 print(obj) 35 data=json.dumps(obj,ensure_ascii=False) 36 f.write(data+"\n") 37 38 if __name__ == '__main__': 39 count=0 40 for i in range(10): 41 main(count) 42 count+=25
5、test
1 # 正则:对字符串的模糊匹配 2 3 # key:元字符(有特殊功能的字符) 4 5 import re 6 7 # re.findall(pattern, string,) # 找到所有的匹配元素,返回列表 8 9 #元字符介绍 10 11 # . :匹配除\n以外的任意符号 12 13 #print(re.findall("a.+d","abcd")) 14 15 16 # ^:从字符串开始位置匹配 17 18 # $:从字符串结尾匹配 19 20 # print(re.findall("^yuan","yuandashj342jhg234")) 21 # print(re.findall("yuan$","yuandashj342jhg234yuan")) 22 23 # * + ? {} :重复 24 25 #print(re.findall("[0-9]{4}","af5324jh523hgj34gkhg53453")) 26 27 28 #贪婪匹配 29 print(re.findall("\d+","af5324jh523hgj34gkhg53453")) 30 31 #非贪婪匹配 32 33 # print(re.findall("\d+?","af5324jh523hgj34gkhg53453")) 34 # print(re.findall("(abc\d)*?","af5324jh523hgj34gkhg53453")) 35 36 # 字符集 []: 起一个或者的意思 37 38 # print(re.findall("a[bc]d","hasdabdjhacd")) 39 40 #注意: * ,+.等元字符都是普通符号, - ^ \ 41 42 # print(re.findall("[0-9]+","dashj342jhg234")) 43 # print(re.findall("[a-z]+","dashj342jhg234")) 44 # 45 # print(re.findall("[^\d]+","d2a2fhj87fgj")) 46 47 48 # ():分组 49 50 # print(re.findall("(ad)+","addd")) 51 # print(re.findall("(ad)+yuan","adddyuangfsdui")) 52 53 # print(re.findall("(?:ad)+yuan","adadyuangfsdui")) 54 # print(re.findall("(?:\d)+yuan","adad678423yuang4234fsdui")) 55 56 #命名分组 57 58 #ret8=re.search(r"(?P<A>\w+)\\aticles\\(?P<id>\d{4})",r"yuan\aticles\1234") 59 #ret8=re.search(r"a\\nb",r"a\nb") 60 #print(ret8) 61 62 # print(ret8.group("id")) 63 # print(ret8.group("A")) 64 65 66 # # | :或 67 # 68 # print(re.findall("www\.(?:oldboy|baidu)\.com","www.oldboy.com")) 69 70 # \:转义 71 72 # 1 后面加一个元字符使其变成普通符号 \. \* 73 # 2 将一些普通符号变成特殊符号 比如 \d \w 74 75 # print(re.findall("\d+\.?\d*\*\d+\.?\d*","-2*6+7*45+1.456*3-8/4")) 76 # print(re.findall("\w","$da@s4 234")) 77 # print(re.findall("a\sb","a badf")) 78 79 # print(re.findall("\\bI","hello I am LIA")) 80 # print(re.findall(r"\dI","hello 654I am LIA")) 81 82 # print(re.findall(r"c\\l","abc\l")) 83 84 85 # re的方法 86 87 88 # re.findall() 89 90 91 # s=re.finditer("\d+","ad324das32") 92 # print(s) 93 # 94 # print(next(s).group()) 95 # print(next(s).group()) 96 97 98 # "(3+7*2+27+7+(4/2+1))+3" 99 100 # search;只匹配第一个结果 101 102 # ret=re.search("\d+","djksf34asd3") 103 # print(ret.group()) 104 # 105 # #match:只在字符串开始的位置匹配 106 # ret=re.match("\d+","423djksf34asd3") 107 # print(ret.group()) 108 109 #split 分割 110 # s2=re.split("\d+","fhd3245jskf54skf453sd",2) 111 # print(s2) 112 # 113 # ret3=re.split("l","hello yuan") 114 # print(ret3) 115 # 116 # #sub: 替换 117 # 118 # ret4=re.sub("\d+","A","hello 234jkhh23",1) 119 # print(ret4) 120 # 121 # ret4=re.subn("\d+","A","hello 234jkhh23") 122 # print(ret4) 123 124 125 #compile: 编译方法 126 # c=re.compile("\d+") 127 # 128 # ret5=c.findall("hello32world53") #== re.findall("\d+","hello32world53") 129 # print(ret5) 130 131 132 #计算:"1 - 2 * ( (60-30*2+-96) - (-4*3)/ (16-3*2) )" 133 134 # s1="1+-2++5" 135 # 136 # def addsub(s): 137 # pass 138 # 139 # def muldiv(s): #(60-30*2+-96) 140 # pass 141 # return (60-60+-96) 142 # 143 # def f(s): 144 # s.replace("+-","-") 145 # 146 # 147 # while re.search("\([^()]+\)", s): 148 # res = re.search("\([^()]+\)", s) #(60-30*2+-96) 149 # res=muldiv(res) 150 # ret=addsub(res) 151 # else: 152 # res = muldiv(res) 153 # ret = addsub(res) 154 155 156 s="2" 157 158 print(res.group())
作业:计算器
扩展:
1 logging模块 2 import logging 3 logging.debug('debug message') 4 logging.info('info message') 5 logging.warning('warning message') 6 logging.error('error message') 7 logging.critical('critical message') 8 9 运行结果: 10 C:\Python36\python.exe C:/Users/Administrator/PycharmProjects/py_fullstack_s4/day34/test.py 11 WARNING:root:warning message 12 ERROR:root:error message 13 CRITICAL:root:critical message 14 可以看出有一个默认的等级:debug--info--warning(默认)--error--critical 15 16 配置的两种方式: 17 1、congfig函数 18 import logging 19 logging.basicConfig(level=logging.DEBUG, 20 format='%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s', 21 datefmt='%a, %d %b %Y %H:%M:%S', 22 filename='/tmp/test.log', 23 filemode='w') 24 25 logging.debug('debug message') 26 logging.info('info message') 27 logging.warning('warning message') 28 logging.error('error message') 29 logging.critical('critical message') 30 level表示日志等级,选择DEBUG的话会将所有的都打印出来,最重要的就是format的内容,具体的配置参数如下: 31 32 可见在logging.basicConfig()函数中可通过具体参数来更改logging模块默认行为,可用参数有 33 filename:用指定的文件名创建FiledHandler(后边会具体讲解handler的概念),这样日志会被存储在指定的文件中。 34 filemode:文件打开方式,在指定了filename时使用这个参数,默认值为“a”还可指定为“w”。 35 format:指定handler使用的日志显示格式。 36 datefmt:指定日期时间格式。 37 level:设置rootlogger(后边会讲解具体概念)的日志级别 38 stream:用指定的stream创建StreamHandler。可以指定输出到sys.stderr,sys.stdout或者文件(f=open('test.log','w')),默认为sys.stderr。若同时列出了filename和stream两个参数,则stream参数会被忽略。 39 40 format参数中可能用到的格式化串: 41 %(name)s Logger的名字 42 %(levelno)s 数字形式的日志级别 43 %(levelname)s 文本形式的日志级别 44 %(pathname)s 调用日志输出函数的模块的完整路径名,可能没有 45 %(filename)s 调用日志输出函数的模块的文件名 46 %(module)s 调用日志输出函数的模块名 47 %(funcName)s 调用日志输出函数的函数名 48 %(lineno)d 调用日志输出函数的语句所在的代码行 49 %(created)f 当前时间,用UNIX标准的表示时间的浮 点数表示 50 %(relativeCreated)d 输出日志信息时的,自Logger创建以 来的毫秒数 51 %(asctime)s 字符串形式的当前时间。默认格式是 “2003-07-08 16:49:45,896”。逗号后面的是毫秒 52 %(thread)d 线程ID。可能没有 53 %(threadName)s 线程名。可能没有 54 %(process)d 进程ID。可能没有 55 %(message)s用户输出的消息 56 2、logger对象 57 上述几个例子中我们了解到了logging.debug()、logging.info()、logging.warning()、logging.error()、logging.critical()(分别用以记录不同级别的日志信息),logging.basicConfig()(用默认日志格式(Formatter)为日志系统建立一个默认的流处理器(StreamHandler),设置基础配置(如日志级别等)并加到root logger(根Logger)中)这几个logging模块级别的函数,另外还有一个模块级别的函数是logging.getLogger([name])(返回一个logger对象,如果没有指定名字将返回root logger) 先看一个最简单的过程: 58 59 import logging 60 61 logger = logging.getLogger() 62 # 创建一个handler,用于写入日志文件 63 fh = logging.FileHandler('test.log') 64 65 # 再创建一个handler,用于输出到控制台 66 ch = logging.StreamHandler() 67 68 formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') 69 70 fh.setFormatter(formatter) 71 ch.setFormatter(formatter) 72 73 logger.addHandler(fh) #logger对象可以添加多个fh和ch对象 74 logger.addHandler(ch) 75 76 logger.debug('logger debug message') 77 logger.info('logger info message') 78 logger.warning('logger warning message') 79 logger.error('logger error message') 80 logger.critical('logger critical message') 81 82 运行结果: 83 2017-04-27 09:19:56,145 - root - WARNING - logger warning message 84 2017-04-27 09:19:56,146 - root - ERROR - logger error message 85 2017-04-27 09:19:56,146 - root - CRITICAL - logger critical message 86 先简单介绍一下,logging库提供了多个组件:Logger、Handler、Filter、Formatter。Logger对象提供应用程序可直接使用的接口,Handler发送日志到适当的目的地,Filter提供了过滤日志信息的方法,Formatter指定日志显示格式。 87 88 Logger是一个树形层级结构,输出信息之前都要获得一个Logger(如果没有显示的获取则自动创建并使用root Logger,如第一个例子所示)。 89 90 logger = logging.getLogger()返回一个默认的Logger也即root Logger,并应用默认的日志级别、Handler和Formatter设置。 当然也可以通过Logger.setLevel(lel)指定最低的日志级别,可用的日志级别有logging.DEBUG、logging.INFO、logging.WARNING、logging.ERROR、logging.CRITICAL。 91 92 Logger.debug()、Logger.info()、Logger.warning()、Logger.error()、Logger.critical()输出不同级别的日志,只有日志等级大于或等于设置的日志级别的日志才会被输出。 93 94 logger.debug('logger debug message') 95 logger.info('logger info message') 96 logger.warning('logger warning message') 97 logger.error('logger error message') 98 logger.critical('logger critical message') 99 只输出了 100 101 2014-05-06 12:54:43,222 - root - WARNING - logger warning message 102 2014-05-06 12:54:43,223 - root - ERROR - logger error message 103 2014-05-06 12:54:43,224 - root - CRITICAL - logger critical message 104 从这个输出可以看出logger = logging.getLogger()返回的Logger名为root。这里没有用logger.setLevel(logging.Debug)显示的为logger设置日志级别,所以使用默认的日志级别WARNIING,故结果只输出了大于等于WARNIING级别的信息。 105 106 序列化模块(json、pickle) 107 什么是序列化? 108 我们把对象(变量)从内存中变成可存储或传输的过程称之为序列化,在Python中叫pickling,在其他语言中也被称之为serialization,marshalling,flattening等等,都是一个意思。 109 110 序列化之后,就可以把序列化后的内容写入磁盘,或者通过网络传输到别的机器上。 111 112 反过来,把变量内容从序列化的对象重新读到内存里称之为反序列化,即unpickling。 113 114 json模块 115 如果我们要在不同的编程语言之间传递对象,就必须把对象序列化为标准格式,比如XML,但更好的方法是序列化为JSON,因为JSON表示出来就是一个字符串,可以被所有语言读取,也可以方便地存储到磁盘或者通过网络传输。JSON不仅是标准格式,并且比XML更快,而且可以直接在Web页面中读取,非常方便。 116 117 JSON表示的对象就是标准的JavaScript语言的对象,JSON和Python内置的数据类型对应如下: 118 119 120 121 #----------------------------序列化 122 123 import json 124 125 dic={'name':'alvin','age':23,'sex':'male'} 126 print(type(dic))#<class 'dict'> 127 j=json.dumps(dic) 128 print(type(j))#<class 'str'> 129 f=open('序列化对象','w') 130 f.write(j) #-------------------等价于json.dump(dic,f) 131 f.close() 132 #-----------------------------反序列化<br> 133 import json 134 f=open('序列化对象') 135 data=json.loads(f.read())# 等价于data=json.load(f) 136 d = {'name':'alvin','age':23,'sex':'male'} 137 138 f = open("filename",'w') 139 140 json.dump(d,f) #与dumps的区别在于将两步合成一步 141 142 f.close() 143 144 pickle模块 145 ##----------------------------序列化 146 import pickle 147 148 dic={'name':'alvin','age':23,'sex':'male'} 149 print(type(dic))#<class 'dict'> 150 j=pickle.dumps(dic) 151 print(type(j))#<class 'bytes'> 152 f=open('序列化对象_pickle','wb')#注意是w是写入str,wb是写入bytes,j是'bytes' 153 f.write(j) #-------------------等价于pickle.dump(dic,f 154 f.close() 155 #-------------------------反序列化 156 import pickle 157 f=open('序列化对象_pickle','rb') 158 data=pickle.loads(f.read())# 等价于data=pickle.load(f) 159 print(data['age']) 160 Pickle的问题和所有其他编程语言特有的序列化问题一样,就是它只能用于Python,并且可能不同版本的Python彼此都不兼容,因此,只能用Pickle保存那些不重要的数据,不能成功地反序列化也没关系。 161 162 re模块 163 就其本质而言,正则表达式(或 RE)是一种小型的、高度专业化的编程语言,(在Python中)它内嵌在Python中,并通过 re 模块实现。正则表达式模式被编译成一系列的字节码,然后由用 C 编写的匹配引擎执行。 164 165 字符匹配(普通字符,元字符): 166 167 1 普通字符:大多数字符和字母都会和自身匹配 >>> re.findall('alvin','yuanaleSxalexwupeiqi') ['alvin'] 168 169 2 元字符:. ^ $ * + ? { } [ ] | ( ) \ 170 171 re.findall("(?:ad)+yuan","adadyuangfsdui") #在(ad)分组中加入: '?:'表示去掉匹配默认的优先级,将字符串完全匹配出来,否则只匹配分组即括号中的内容 172 173 管道符:| 表示匹配它两边的内容 174 175 176 177 元字符之转义符\ 178 179 反斜杠后边跟元字符去除特殊功能,比如\. 180 反斜杠后边跟普通字符实现特殊功能,比如\d 181 182 \d 匹配任何十进制数;它相当于类 [0-9]。 183 \D 匹配任何非数字字符;它相当于类 [^0-9]。 184 \s 匹配任何空白字符;它相当于类 [ \t\n\r\f\v]。 185 \S 匹配任何非空白字符;它相当于类 [^ \t\n\r\f\v]。 186 \w 匹配任何字母数字字符;它相当于类 [a-zA-Z0-9_]。 187 \W 匹配任何非字母数字字符;它相当于类 [^a-zA-Z0-9_] 188 \b 匹配一个特殊字符边界,比如空格 ,&,#等 189 使用\b的时候需要注意,因为它在ASCII码表中有特殊的意义,表示退格,在python中使用正则表达式,会将代码先交给Python解释器进行解释,而解释器也支持‘\’转义符号,然后再交给正则表达式进行匹配,故使用时应该用如下形式: 190 191 ret=re.findall('c\\\\l','abc\le') 192 print(ret) 193 执行结果为:['c\\l'] 194 195 196 re模块下的常用方法 197 import re 198 #1 199 re.findall('a','alvin yuan') #返回所有满足匹配条件的结果,放在列表里 200 #2 201 re.search('a','alvin yuan').group() #函数会在字符串内查找模式匹配,只到找到第一个匹配然后返回一个包含匹配信息的对象,该对象可以 202 # 通过调用group()方法得到匹配的字符串,如果字符串没有匹配,则返回None。 203 #3 204 re.match('a','abc').group() #同search,不过尽在字符串开始处进行匹配 205 #4 206 ret=re.split('[ab]','abcd') #先按'a'分割得到''和'bcd',在对''和'bcd'分别按'b'分割,可跟分割次数参数 207 print(ret)#['', '', 'cd'] 208 #5 209 ret=re.sub('\d','abc','alvin5yuan6',1) 210 print(ret)#alvinabcyuan6 211 ret=re.subn('\d','abc','alvin5yuan6') 212 print(ret)#('alvinabcyuanabc', 2) 213 #6 214 obj=re.compile('\d{3}') 215 ret=obj.search('abc123eeee') 216 print(ret.group())#123 217 218 219 220 import re 221 ret=re.finditer('\d','ds3sy4784a') 222 print(ret) #<callable_iterator object at 0x10195f940> 223 print(next(ret).group()) 224 print(next(ret).group()) 225 226 227 import re 228 ret=re.findall('www.(baidu|oldboy).com','www.oldboy.com') 229 print(ret)#['oldboy'] 这是因为findall会优先把匹配结果组里内容返回,如果想要匹配结果,取消权限即可 230 ret=re.findall('www.(?:baidu|oldboy).com','www.oldboy.com') 231 print(ret)#['www.oldboy.com'] 232 命名分组
1 *** 2 #logging模块 3 import logging 4 logging.debug('debug message') 5 logging.info('info message') 6 logging.warning('warning message') 7 logging.error('error message') 8 logging.critical('critical message') 9 10 运行结果: 11 C:\Python36\python.exe C:/Users/Administrator/PycharmProjects/py_fullstack_s4/day34/test.py 12 WARNING:root:warning message 13 ERROR:root:error message 14 CRITICAL:root:critical message 15 16 ***可以看出有一个默认的等级:debug--info--warning(默认)--error--critical*** 17 18 ##**配置的两种方式:** 19 ###1、congfig函数 20 21 import logging 22 logging.basicConfig(level=logging.DEBUG, 23 format='%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s', 24 datefmt='%a, %d %b %Y %H:%M:%S', 25 filename='/tmp/test.log', 26 filemode='w') 27 28 logging.debug('debug message') 29 logging.info('info message') 30 logging.warning('warning message') 31 logging.error('error message') 32 logging.critical('critical message') 33 34 ***level表示日志等级,选择DEBUG的话会将所有的都打印出来,最重要的就是format的内容,具体的配置参数如下:*** 35 36 可见在logging.basicConfig()函数中可通过具体参数来更改logging模块默认行为,可用参数有 37 filename:用指定的文件名创建FiledHandler(后边会具体讲解handler的概念),这样日志会被存储在指定的文件中。 38 filemode:文件打开方式,在指定了filename时使用这个参数,默认值为“a”还可指定为“w”。 39 format:指定handler使用的日志显示格式。 40 datefmt:指定日期时间格式。 41 level:设置rootlogger(后边会讲解具体概念)的日志级别 42 stream:用指定的stream创建StreamHandler。可以指定输出到sys.stderr,sys.stdout或者文件(f=open('test.log','w')),默认为sys.stderr。若同时列出了filename和stream两个参数,则stream参数会被忽略。 43 44 format参数中可能用到的格式化串: 45 %(name)s Logger的名字 46 %(levelno)s 数字形式的日志级别 47 %(levelname)s 文本形式的日志级别 48 %(pathname)s 调用日志输出函数的模块的完整路径名,可能没有 49 %(filename)s 调用日志输出函数的模块的文件名 50 %(module)s 调用日志输出函数的模块名 51 %(funcName)s 调用日志输出函数的函数名 52 %(lineno)d 调用日志输出函数的语句所在的代码行 53 %(created)f 当前时间,用UNIX标准的表示时间的浮 点数表示 54 %(relativeCreated)d 输出日志信息时的,自Logger创建以 来的毫秒数 55 %(asctime)s 字符串形式的当前时间。默认格式是 “2003-07-08 16:49:45,896”。逗号后面的是毫秒 56 %(thread)d 线程ID。可能没有 57 %(threadName)s 线程名。可能没有 58 %(process)d 进程ID。可能没有 59 %(message)s用户输出的消息 60 61 62 ###2、logger对象 63 >上述几个例子中我们了解到了logging.debug()、logging.info()、logging.warning()、logging.error()、logging.critical()(分别用以记录不同级别的日志信息),logging.basicConfig()(用默认日志格式(Formatter)为日志系统建立一个默认的流处理器(StreamHandler),设置基础配置(如日志级别等)并加到root logger(根Logger)中)这几个logging模块级别的函数,另外还有一个模块级别的函数是logging.getLogger([name])(返回一个logger对象,如果没有指定名字将返回root logger) 64 先看一个最简单的过程: 65 66 import logging 67 68 logger = logging.getLogger() 69 # 创建一个handler,用于写入日志文件 70 fh = logging.FileHandler('test.log') 71 72 # 再创建一个handler,用于输出到控制台 73 ch = logging.StreamHandler() 74 75 formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') 76 77 fh.setFormatter(formatter) 78 ch.setFormatter(formatter) 79 80 logger.addHandler(fh) #logger对象可以添加多个fh和ch对象 81 logger.addHandler(ch) 82 83 logger.debug('logger debug message') 84 logger.info('logger info message') 85 logger.warning('logger warning message') 86 logger.error('logger error message') 87 logger.critical('logger critical message') 88 89 运行结果: 90 2017-04-27 09:19:56,145 - root - WARNING - logger warning message 91 2017-04-27 09:19:56,146 - root - ERROR - logger error message 92 2017-04-27 09:19:56,146 - root - CRITICAL - logger critical message 93 94 >先简单介绍一下,logging库提供了多个组件:Logger、Handler、Filter、Formatter。Logger对象提供应用程序可直接使用的接口,Handler发送日志到适当的目的地,Filter提供了过滤日志信息的方法,Formatter指定日志显示格式。 95 > 96 Logger是一个树形层级结构,输出信息之前都要获得一个Logger(如果没有显示的获取则自动创建并使用root Logger,如第一个例子所示)。 97 98 > logger = logging.getLogger()返回一个默认的Logger也即root Logger,并应用默认的日志级别、Handler和Formatter设置。 99 当然也可以通过Logger.setLevel(lel)指定最低的日志级别,可用的日志级别有logging.DEBUG、logging.INFO、logging.WARNING、logging.ERROR、logging.CRITICAL。 100 101 >Logger.debug()、Logger.info()、Logger.warning()、Logger.error()、Logger.critical()输出不同级别的日志,只有日志等级大于或等于设置的日志级别的日志才会被输出。 102 103 logger.debug('logger debug message') 104 logger.info('logger info message') 105 logger.warning('logger warning message') 106 logger.error('logger error message') 107 logger.critical('logger critical message') 108 109 >只输出了 110 111 2014-05-06 12:54:43,222 - root - WARNING - logger warning message 112 2014-05-06 12:54:43,223 - root - ERROR - logger error message 113 2014-05-06 12:54:43,224 - root - CRITICAL - logger critical message 114 >从这个输出可以看出logger = logging.getLogger()返回的Logger名为root。这里没有用logger.setLevel(logging.Debug)显示的为logger设置日志级别,所以使用默认的日志级别WARNIING,故结果只输出了大于等于WARNIING级别的信息。 115 116 *** 117 #序列化模块(json、pickle) 118 ###什么是序列化? 119 >我们把对象(变量)从内存中变成可存储或传输的过程称之为序列化,在Python中叫pickling,在其他语言中也被称之为serialization,marshalling,flattening等等,都是一个意思。 120 121 >序列化之后,就可以把序列化后的内容写入磁盘,或者通过网络传输到别的机器上。 122 123 >反过来,把变量内容从序列化的对象重新读到内存里称之为反序列化,即unpickling。 124 125 ##json模块 126 >如果我们要在不同的编程语言之间传递对象,就必须把对象序列化为标准格式,比如XML,但更好的方法是序列化为JSON,因为JSON表示出来就是一个字符串,可以被所有语言读取,也可以方便地存储到磁盘或者通过网络传输。JSON不仅是标准格式,并且比XML更快,而且可以直接在Web页面中读取,非常方便。 127 128 >JSON表示的对象就是标准的JavaScript语言的对象,JSON和Python内置的数据类型对应如下: 129 130 ![](http://i.imgur.com/qbLGmCl.png) 131 132 133 #----------------------------序列化 134 135 import json 136 137 dic={'name':'alvin','age':23,'sex':'male'} 138 print(type(dic))#<class 'dict'> 139 j=json.dumps(dic) 140 print(type(j))#<class 'str'> 141 f=open('序列化对象','w') 142 f.write(j) #-------------------等价于json.dump(dic,f) 143 f.close() 144 #-----------------------------反序列化<br> 145 import json 146 f=open('序列化对象') 147 data=json.loads(f.read())# 等价于data=json.load(f) 148 149 >d = {'name':'alvin','age':23,'sex':'male'} 150 > 151 >f = open("filename",'w') 152 > 153 >json.dump(d,f) #与dumps的区别在于将两步合成一步 154 > 155 >f.close() 156 157 158 ##pickle模块 159 ##----------------------------序列化 160 import pickle 161 162 dic={'name':'alvin','age':23,'sex':'male'} 163 print(type(dic))#<class 'dict'> 164 j=pickle.dumps(dic) 165 print(type(j))#<class 'bytes'> 166 f=open('序列化对象_pickle','wb')#注意是w是写入str,wb是写入bytes,j是'bytes' 167 f.write(j) #-------------------等价于pickle.dump(dic,f 168 f.close() 169 #-------------------------反序列化 170 import pickle 171 f=open('序列化对象_pickle','rb') 172 data=pickle.loads(f.read())# 等价于data=pickle.load(f) 173 print(data['age']) 174 >Pickle的问题和所有其他编程语言特有的序列化问题一样,就是它只能用于Python,并且可能不同版本的Python彼此都不兼容,因此,只能用Pickle保存那些不重要的数据,不能成功地反序列化也没关系。 175 176 *** 177 #re模块 178 179 >就其本质而言,正则表达式(或 RE)是一种小型的、高度专业化的编程语言,(在Python中)它内嵌在Python中,并通过 re 模块实现。正则表达式模式被编译成一系列的字节码,然后由用 C 编写的匹配引擎执行。 180 181 >字符匹配(普通字符,元字符): 182 183 >>1 普通字符:大多数字符和字母都会和自身匹配 184 >>> re.findall('alvin','yuanaleSxalexwupeiqi') 185 ['alvin'] 186 187 >>2 元字符:. ^ $ * + ? { } [ ] | ( ) \ 188 189 190 **re.findall("(?:ad)+yuan","adadyuangfsdui") #在(ad)分组中加入: '?:'表示去掉匹配默认的优先级,将字符串完全匹配出来,否则只匹配分组即括号中的内容** 191 192 **管道符:| 表示匹配它两边的内容** 193 194 ![](http://i.imgur.com/lnTzTy9.png) 195 196 元字符之转义符\ 197 198 反斜杠后边跟元字符去除特殊功能,比如\. 199 反斜杠后边跟普通字符实现特殊功能,比如\d 200 201 \d 匹配任何十进制数;它相当于类 [0-9]。 202 \D 匹配任何非数字字符;它相当于类 [^0-9]。 203 \s 匹配任何空白字符;它相当于类 [ \t\n\r\f\v]。 204 \S 匹配任何非空白字符;它相当于类 [^ \t\n\r\f\v]。 205 \w 匹配任何字母数字字符;它相当于类 [a-zA-Z0-9_]。 206 \W 匹配任何非字母数字字符;它相当于类 [^a-zA-Z0-9_] 207 \b 匹配一个特殊字符边界,比如空格 ,&,#等 208 209 **使用\b的时候需要注意,因为它在ASCII码表中有特殊的意义,表示退格,在python中使用正则表达式,会将代码先交给Python解释器进行解释,而解释器也支持‘\’转义符号,然后再交给正则表达式进行匹配,故使用时应该用如下形式:** 210 211 ret=re.findall('c\\\\l','abc\le') 212 print(ret) 213 执行结果为:['c\\l'] 214 215 ![](http://i.imgur.com/Rvkvgi3.png) 216 217 ###re模块下的常用方法 218 219 220 import re 221 #1 222 re.findall('a','alvin yuan') #返回所有满足匹配条件的结果,放在列表里 223 #2 224 re.search('a','alvin yuan').group() #函数会在字符串内查找模式匹配,只到找到第一个匹配然后返回一个包含匹配信息的对象,该对象可以 225 # 通过调用group()方法得到匹配的字符串,如果字符串没有匹配,则返回None。 226 #3 227 re.match('a','abc').group() #同search,不过尽在字符串开始处进行匹配 228 #4 229 ret=re.split('[ab]','abcd') #先按'a'分割得到''和'bcd',在对''和'bcd'分别按'b'分割,可跟分割次数参数 230 print(ret)#['', '', 'cd'] 231 #5 232 ret=re.sub('\d','abc','alvin5yuan6',1) 233 print(ret)#alvinabcyuan6 234 ret=re.subn('\d','abc','alvin5yuan6') 235 print(ret)#('alvinabcyuanabc', 2) 236 #6 237 obj=re.compile('\d{3}') 238 ret=obj.search('abc123eeee') 239 print(ret.group())#123 240 241 242 243 import re 244 ret=re.finditer('\d','ds3sy4784a') 245 print(ret) #<callable_iterator object at 0x10195f940> 246 print(next(ret).group()) 247 print(next(ret).group()) 248 249 250 import re 251 ret=re.findall('www.(baidu|oldboy).com','www.oldboy.com') 252 print(ret)#['oldboy'] 这是因为findall会优先把匹配结果组里内容返回,如果想要匹配结果,取消权限即可 253 ret=re.findall('www.(?:baidu|oldboy).com','www.oldboy.com') 254 print(ret)#['www.oldboy.com'] 255 256 ###命名分组 257 258 ![](http://i.imgur.com/Q6d7y97.png)