常用模块(time、random、hashlib 、os、sys、logging、json、pickle、re )
一 time模块
时间表示形式
在Python中,通常有这三种方式来表示时间:时间戳(timestamp)、格式化时间字符串(Format String)、结构化时间字符串(struct time):
(1)时间戳(timestamp) :通常来说,时间戳表示的是从1970年1月1日00:00:00开始按秒计算的偏移量。我们运行“time.time()”,返回的是float类型。
(2)格式化时间字符串(Format String):time.strftime("%Y-%m-%d %X") Y:年 m:月 d:日 X:时分秒
(3)结构化时间字符串(struct time) :struct time元组共有9个元素共九个元素:(年tm_year,月tm_mon,日tm_mon,时tm_hour,分tm_min,秒tm_sec,这周的第几天 tm_wday,一年中第几天tm_yday等),time.localtime()
小结:时间戳是计算机能够识别的时间;时间字符串是人能够看懂的时间;元组则是用来操作时间的
# <1> 时间戳 >>> import time >>> time.time() #--------------返回当前时间的时间戳 1493136727.099066 # <2> 格式化时间字符串 >>> time.strftime("%Y-%m-%d %X") '2017-04-26 00:32:18' # <3> 结构化时间字符串 >>> time.localtime() time.struct_time(tm_year=2017, tm_mon=4, tm_mday=26, tm_hour=0, tm_min=32, tm_sec=42, tm_wday=2, tm_yday=116, tm_isdst=0)
几种时间形式的转换
(1)

#一 时间戳<---->结构化时间字符串: localtime/gmtime mktime >>> time.localtime(3600*24) time.struct_time(tm_year=1970, tm_mon=1, tm_mday=2, tm_hour=8, tm_min=0, tm_sec=0, tm_wday=4, tm_yday=2, tm_isdst=0)
>>> time.gmtime(3600*24)
time.struct_time(tm_year=1970, tm_mon=1, tm_mday=2, tm_hour=0, tm_min=0, tm_sec=0, tm_wday=4, tm_yday=2, tm_isdst=0) >>> time.mktime(time.localtime()) 1513694512.0 #结构化时间字符串<---->格式化时间字符串: strftime/strptime >>> time.strftime("%Y-%m-%d %X", time.localtime()) 2017-12-19 22:43:32
>>> time.strptime("2017-03-16","%Y-%m-%d")
time.struct_time(tm_year=2017, tm_mon=3, tm_mday=16, tm_hour=0, tm_min=0, tm_sec=0, tm_wday=3, tm_yday=75, tm_isdst=-1)
(2)

>>> time.asctime(time.localtime(312343423)) #结构化时间字符串转化为格式化时间字符串 'Sun Nov 25 10:03:43 1979' >>> time.ctime(312343423) #时间戳转化为格式化时间字符串 'Sun Nov 25 10:03:43 1979'
%a %b %d %H:%M:%S %Y 星期 月 日 时:分:秒 年
1 #--------------------------其他方法 2 # sleep(secs) 3 # 线程推迟指定的时间运行,单位为秒。
二 random模块
>>> import random >>> random.random() # 大于0且小于1之间的小数 0.7664338663654585 >>> random.randint(1,5) # 大于等于1且小于等于5之间的整数 2 >>> random.randrange(1,3) # 大于等于1且小于3之间的整数 1 >>> random.choice([1,'23',[4,5]]) # #1或者23或者[4,5] 1 >>> random.sample([1,'23',[4,5]],2) # #列表元素任意2个组合 [[4, 5], '23'] >>> random.uniform(1,3) #大于1小于3的小数 1.6270147180533838 >>> item=[1,3,5,7,9] >>> random.shuffle(item) # 打乱次序 >>> item [5, 1, 3, 7, 9] >>> random.shuffle(item) >>> item [5, 9, 7, 1, 3]
练习:生成验证码
#以字母和数字,生成五个随机数验证码
import random def v_code(): code = '' for i in range(5): num=random.randint(0,9) alf1=chr(random.randint(65,90)) alf2 = chr(random.randint(97,122)) add=random.choice([num,alf1,alf2]) code="".join([code,str(add)]) return code print(v_code())
三 hashlib
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?'.encode("utf-8")) print md5.hexdigest() 计算结果如下: d26a53750bc40b38b65a520292f69306
如果数据量很大,可以分块多次调用update(),最后计算的结果是一样的:
md5 = hashlib.md5() md5.update('how to use md5 in '.encode("utf-8")) md5.update('python hashlib?'.encode("utf-8")) print md5.hexdigest()
MD5是最常见的摘要算法,速度很快,生成结果是固定的128 bit字节,通常用一个32位的16进制字符串表示。另一种常见的摘要算法是SHA1,调用SHA1和调用MD5完全类似:
import hashlib sha1 = hashlib.sha1() sha1.update('how to use sha1 in '.encode("utf-8")) sha1.update('python hashlib?'.encode("utf-8")) print sha1.hexdigest()
SHA1的结果是160 bit字节,通常用一个40位的16进制字符串表示。比SHA1更安全的算法是SHA256和SHA512,不过越安全的算法越慢,而且摘要长度更长。
摘要算法应用
数据库密码加密:“加盐”
hashlib.md5("salt".encode("utf8"))
四 os模块
os模块是与操作系统交互的一个接口
''' os.getcwd() 获取当前工作目录,即当前python脚本工作的目录路径 os.chdir(r"文件路径") 改变当前脚本工作目录;相当于shell下cd os.curdir 返回当前目录: ('.') os.pardir 获取当前目录的父目录字符串名:('..') os.makedirs('dirname1/dirname2') 可生成多层递归目录 os.mknod("textname") 创建空文件
os.removedirs('文件路径') 若目录为空,则删除,并递归到上一级目录,如若也为空,则删除,依此类推 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')#获取文件/目录信息 结果为一个列表st_atime:最后存储时间 st_mtime 修改时间 st_ctime 创建时间
#网站浏览,缓存后再次访问,判断创建时间和有修改时间是否相同,如果不同,则需要到原网站去下载
os.path.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.realpath(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[, ...]]) 将多个路径组合后返回,第一个绝对路径之前的参数将被忽略
#路径拼接print(s1+os.sep+s2) ret =os.path.jion(s1,s2)#推荐
os.path.getatime(path) 返回path所指向的文件或者目录的最后存取时间
os.path.getmtime(path) 返回path所指向的文件或者目录的最后修改时间
os.path.getsize(path) 返回path的大小 '''
os.path.normcase 规范化路径
在Linux和Mac平台上,该函数会原样返回path,在windows平台上会将路径中所有字符转换为小写,并将所有斜杠转换为饭斜杠。 >>> os.path.normcase('c:/windows\\system32\\') 'c:\\windows\\system32\\' 规范化路径,如..和/ >>> os.path.normpath('c://windows\\System32\\../Temp/') 'c:\\windows\\Temp'
os.popen(), os.system()区别
os.system的结果只是命令执行结果的返回值,执行成功为0:
>>> a=os.system('ls') Applications Movies python-oldboy Applications (Parallels) Music python3.sublime-build Desktop Pictures rpro.log Documents Public test.py Downloads PycharmProjects test.pyc GitHub_source Python_Assignment Library oradiag_shane >>> a 0
用os.popen就可以读出执行的内容,popen返回的是file read的对象,对其进行读取使用read(),就可看到执行的输出:
>>> b=os.popen('ls') >>> b.read() 'Applications\nApplications (Parallels)\nDesktop\nDocuments\nDownloads\nGitHub_source\nLibrary\nMovies\nMusic\nPictures\nPublic\nPycharmProjects\nPython_Assignment\noradiag_shane\npython-oldboy\npython3.sublime-build\nrpro.log\ntest.py\ntest.pyc\n' >>> type(b) <class 'os._wrap_close'> >>>
可以看出,输出的结果比较特殊,带换行符\n
五 sys模块
sys.argv 命令行参数List,第一个元素是程序本身路径
sys.platform 返回操作系统平台名称
sys.path 返回模块的搜索路径,初始化时使用PYTHONPATH环境变量的值。
sys.path.insert(0,'module path’)、
sys.path.append(“module path”)
sys.exit(n) 退出正在运行的程序,正常退出时exit(0)
sys.version 获取Python解释程序的版本信息
sys.maxint 最大的Int值 #python3不可用
sys.getsizeof(data) 得到数据大小
sys.argv 命令行参数List,第一个元素是程序本身路径
# encoding: utf-8 # filename: argv_test.py import sys # 获取脚本名字 print 'The name of this program is: %s' %(sys.argv[0]) # 获取参数列表 print 'The command line arguments are:' for i in sys.argv: print i # 统计参数个数 print 'There are %s arguments.'%(len(sys.argv)-1)
结果:
E:\p>python argv_test.py arg1 arg2 arg3 The name of this program is: argv_test.py The command line arguments are: argv_test.py arg1 arg2 arg3 There are 3 arguments.
六 logging模块
6.1 函数式简单配置(不能同时向屏幕和文件输出日志信息)
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='%Y-%m-%d %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')
配置参数:
logging.basicConfig()函数中可通过具体参数来更改logging模块默认行为,可用参数有: filename:用指定的文件名创建FiledHandler,这样日志会被存储在指定的文件中。 filemode:文件打开方式,在指定了filename时使用这个参数,默认值为“a”还可指定为“w”。 format:指定handler使用的日志显示格式。 datefmt:指定日期时间格式。 level:设置rootlogger(后边会讲解具体概念)的日志级别 stream:用指定的stream创建StreamHandler。可以指定输出到sys.stderr,sys.stdout或者文件(f=open(‘test.log’,’w’)),默认为sys.stderr。若同时列出了filename和stream两个参数,则stream参数会被忽略。 format参数中可能用到的格式化串: %(name)s Logger的名字 %(levelno)s 数字形式的日志级别 %(levelname)s 文本形式的日志级别 %(pathname)s 调用日志输出函数的模块的完整路径名,可能没有 %(filename)s 调用日志输出函数的模块的文件名 %(module)s 调用日志输出函数的模块名 %(funcName)s 调用日志输出函数的函数名 %(lineno)d 调用日志输出函数的语句所在的代码行 %(created)f 当前时间,用UNIX标准的表示时间的浮 点数表示 %(relativeCreated)d 输出日志信息时的,自Logger创建以 来的毫秒数 %(asctime)s 字符串形式的当前时间。默认格式是 “2003-07-08 16:49:45,896”。逗号后面的是毫秒 %(thread)d 线程ID。可能没有 %(threadName)s 线程名。可能没有 %(process)d 进程ID。可能没有 %(message)s用户输出的消息
6.2 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.setLevel(logging.DEBUG) #指定输出的日志级别(文件和控制台)
logger.handlers.clear()# 清除控制句柄
logger.addHandler(fh) #logger对象可以添加多个fh和ch对象 logger.addHandler(ch) #logger对象可以添加多个fh和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)设置级别。
七 序列化模块
之前我们学习过用eval内置方法可以将一个字符串转成python对象,不过,eval方法是有局限性的,对于普通的数据类型,json.loads和eval都能用,但遇到特殊类型的时候,eval就不管用了,所以eval的重点还是通常用来执行一个字符串表达式,并返回表达式的值。
什么是序列化?
我们把对象(变量)从内存中变成可存储或传输的过程称之为序列化,在Python中叫pickling,在其他语言中也被称之为serialization,marshalling,flattening等等,都是一个意思。序列化之后,就可以把序列化后的内容写入磁盘,或者通过网络传输到别的机器上。反过来,把变量内容从序列化的对象重新读到内存里称之为反序列化,即unpickling。
json (只能序列化特定类型的数据,如果在文件自己写入json格式的数据,也能反序列化)
如果我们要在不同的编程语言之间传递对象,就必须把对象序列化为标准格式,比如XML,但更好的方法是序列化为JSON,因为JSON表示出来就是一个字符串,可以被所有语言读取,也可以方便地存储到磁盘或者通过网络传输。JSON不仅是标准格式,并且比XML更快,而且可以直接在Web页面中读取,非常方便。
JSON表示的对象就是标准的JavaScript语言的对象一个子集,JSON和Python内置的数据类型对应如下:
dumps是将dict转化成str格式,loads是将str转化成dict格式。
dump和load也是类似的功能,只是与文件操作结合起来了。
json.dump(dict,f)
data=json.dumps(dict)
f.write(data)
data=json.load(f)
data=json.loads(f.read())

import json i=10 s='hello' t=(1,4,6) l=[3,5,7] d={'name':"yuan"} json_str1=json.dumps(i) json_str2=json.dumps(s) json_str3=json.dumps(t) json_str4=json.dumps(l) json_str5=json.dumps(d) print(json_str1) #'10' print(json_str2) #'"hello"' print(json_str3) #'[1, 4, 6]' #元组对应的格式变化了,是json数据类型了 print(json_str4) #'[3, 5, 7]' print(json_str5) #'{"name": "yuan"}' #键为“”引起来
python在文本中的使用:
#----------------------------序列化 import json dic={'name':'alvin','age':23,'sex':'male'} print(type(dic))#<class 'dict'> data=json.dumps(dic) print("type",type(data))#<class 'str'> print("data",data) f=open('序列化对象','w') f.write(data) #-------------------等价于json.dump(dic,f),相当于进行了两步操作,一、转换成json字符串,将json字符串写入文件 f.close() #-----------------------------反序列化<br> import json f=open('序列化对象') new_data=json.loads(f.read())# 等价于data=json.load(f) print(type(new_data))
pickle(能处理任何数据类型,只有python解释器解读,处理成字节,文件不可读)
##----------------------------序列化 import pickle dic={'name':'alvin','age':23,'sex':'male'} print(type(dic))#<class 'dict'> j=pickle.dumps(dic) print(type(j))#<class 'bytes'> f=open('序列化对象_pickle','wb')#注意是w是写入str,wb是写入bytes,j是'bytes' f.write(j) #-------------------等价于pickle.dump(dic,f) f.close() #-------------------------反序列化 import pickle f=open('序列化对象_pickle','rb') data=pickle.loads(f.read())# 等价于data=pickle.load(f) print(data['age'])
re模块(正则,对字符串的模糊匹配)
就其本质而言,正则表达式(或 RE)是一种小型的、高度专业化的编程语言,(在Python中)它内嵌在Python中,并通过 re 模块实现。正则表达式模式被编译成一系列的字节码,然后由用 C 编写的匹配引擎执行。
import re #1 re.findall re.findall('a','alvin yuan') #返回所有满足匹配条件的结果,放在列表里
#2 re.search re.search('a','alvin yuan').group()
# 函数会在字符串内查找模式匹配,只到找到第一个匹配然后返回一个包含匹配信息的对象,该对象可以 # 通过调用group()方法得到匹配的字符串,如果字符串没有匹配,re.search()没有匹配,则返回None。 #3 re,match re.match('a','abc').group() #同search,不过在字符串开始处进行匹配 #4 re.split ret=re.split('[ab]','abcd') #先按'a'分割得到''和'bcd',在对''和'bcd'分别按'b'分割 print(ret)#['', '', 'cd'] #5 re.sub su.subn ret=re.sub('\d','abc','alvin5yuan6',1) #(规则,替换内容,字符串,要替换的次数) print(ret)#alvinabcyuan6 ret=re.subn('\d','abc','alvin5yuan6') #替换所有符合规则的字符串,以元组的形式返回替换结果合替换次数 print(ret)#('alvinabcyuanabc', 2) #6 re.compile 编译规则,存起来随时调用 obj=re.compile('\d{3}') ret=obj.search('abc123eeee') print(ret.group())#123
字符匹配(普通字符,元字符):
1 普通字符:大多数字符和字母都会和自身匹配
2 元字符:. ^ $ * + ? { } [ ] | ( ) \
元字符之.* + ? { } ^ $
.通配符(除了\n换行符)
* [0,+00] 零到无穷多次
+ [1,+00] 一到无穷多次
? [0,1] 零到一次
{} {n,} n到无穷次
^:从字符串开始位置匹配
$:从字符串结尾匹配
import re ret=re.findall('a..in','helloalvin') print(ret)#['alvin'] ret=re.findall('^a...n','alvinhelloawwwn') print(ret)#['alvin'] ret=re.findall('a...n$','alvinhelloawwwn') print(ret)#['awwwn'] ret=re.findall('a...n$','alvinhelloawwwn') print(ret)#['awwwn'] ret=re.findall('abc*','abcccc')#贪婪匹配[0,+oo] print(ret)#['abcccc'] ret=re.findall('abc+','abccc')#[1,+oo] print(ret)#['abccc'] ret=re.findall('abc?','abccc')#[0,1] print(ret)#['abc'] ret=re.findall('abc{1,4}','abccc') print(ret)#['abccc'] 贪婪匹配
注意:前面的*,+,?等都是贪婪匹配,也就是尽可能匹配,后面加?号使其变成惰性匹配
ret=re.findall('abc*?','abcccccc') print(ret)#['ab']
元字符之字符集[]:取一个或者的意思 注意: * + . 等元字符都是普通符号, - ^ \ [ ]是有意义的
[^]里面的内容取反
#--------------------------------------------字符集[] ret=re.findall('a[bc]d','acd') print(ret)#['acd'] ret=re.findall('[a-z]','acd') print(ret)#['a', 'c', 'd'] ret=re.findall('[.*+]','a.cd+') print(ret)#['.', '+'] #在字符集里有功能的符号: - ^ \ ret=re.findall('[1-9]','45dha3') print(ret)#['4', '5', '3'] ret=re.findall('[^ab]','45bdha3') print(ret)#['4', '5', 'd', 'h', '3'] ret=re.findall('[\d]','45bdha3') print(ret)#['4', '5', '3']
元字符之分组() 优先显示分组的内容
去掉组的优先级
print(re.findall("(ad)+","addd")) #['ad'] print(re.findall("(ad)+yuan","adddyuangfsdui")) #[] print(re.findall("(?:ad)+yuan","adadyuangfsdui")) #['adadyuan'] 去掉组的优先级 print(re.findall("(?:\d)+yuan","adad678423yuang4234fsdui")) #['678423yuan']
命名分组
r表示原生字符,也就是说不转义字符不需要再次被转义
比如你要表示‘\n’,可以这样:r'\n' 但是如果你不用原生字符 而是用字符串你得这样:‘\\n’
ret8=re.search(r"(?P<A>\w+)\\aticles\\(?P<id>\d{4})",r"yuan\aticles\1234") #给组命名print(ret8.group("id")) #调取组的内容 print(ret8.group("A"))
元字符之|
import re ret=re.findall('www.(baidu|oldboy).com','www.oldboy.com') print(ret)#['oldboy'] 这是因为findall会优先把匹配结果组里内容返回,如果想要匹配结果,取消权限即可 ret=re.findall('www.(?:baidu|oldboy).com','www.oldboy.com') print(ret)#['www.oldboy.com']
元字符之转义符\
反斜杠后边跟元字符去除特殊功能,比如\.
反斜杠后边跟普通字符实现特殊功能,比如\d
\d 匹配任何十进制数;它相当于类 [0-9]。
\D 匹配任何非数字字符;它相当于类 [^0-9]。
\s 匹配任何空白字符;它相当于类 [ \t\n\r\f\v]。
\S 匹配任何非空白字符;它相当于类 [^ \t\n\r\f\v]。
\w 匹配任何字母数字字符;它相当于类 [a-zA-Z0-9_]。
\W 匹配任何非字母数字字符;它相当于类 [^a-zA-Z0-9_]
\b 匹配一个特殊字符边界,比如空格 ,&,#等
ret=re.findall('I\b','I am LIST') print(ret)#[] ret=re.findall(r'I\b','I am LIST') #r将'I\b'转为原生字符串,\b匹配一个特殊边界 print(ret)#['I']
现在我们聊一聊\,先看下面两个匹配:
#-----------------------------eg1: import re ret=re.findall('c\l','abc\le') print(ret)#[] ret=re.findall('c\\l','abc\le') print(ret)#[] ret=re.findall('c\\\\l','abc\le') print(ret)#['c\\l'] #显示的是两个\\,其实是一个\ ret=re.findall(r'c\\l','abc\le') print(ret)#['c\\l'] #-----------------------------eg2: #之所以选择\b是因为\b在ASCII表中是有意义的,\b在ASCII中退格的意思,拿给正则表达式就不能识别了 m = re.findall('\bblow', 'blow') print(m) #[] m = re.findall(r'\bblow', 'blow') #r先将\b不要转义,当成原生字符串拿给正则表达式 print(m) #['blow']


浙公网安备 33010602011771号