Python23 内置模块讲解
模块的分类
参考博客Http://www.cnblogs.com/alex3714/articles/5161349.html
python中的模块分为三大类:
1.标准库(内置模块)
2.开源模块(第三方模块)
3.自定义模块(自己写的.py文件模块)
标准库
1.time
UTC是世界标准时间,中国是在东8区(GMT+8)
导入time模块,通过time.timezone查看时区,28800是秒单位,除60是分钟,在除60的结果是小时,也就是说中国时区比UTC早8个小时。
1.1 time.time
time.time()查看时间戳,以秒为单位,这个数字实际没什么大的意义,只不过是从1970年开始算起到当前经历了多少秒。从1970年开始算是因为这是Unix诞生的时间。
1507535507/60/60/24/365(最终求的是多少年),结果是从1970年到现在为47年,1970+47就是今年的2017年。
1.2 time.sleep
用于延迟,图中定义了延迟3秒
在写代码时,可以利用time.sleep延迟多久后在继续执行后续的代码。
1.3 time.gmtime
以元组的方式转换时间戳,显示转换的时间,默认显示的是当前UTC的时间(不是中国东八区时间),比东八区差了8个小时。
时间格式为:年、月、日、小时、分钟、秒、本周第几天(从0开始算)、本年第几天(1-366)、是否是夏令时
在括号中输入以秒为单位的数字进行计算UTC的时间(从1970年开始算)
1.4 time.localtime
以元组的方式转换时间戳,显示的是本地的时间。
元组中的时间数据类似字典,当想要取出时间时,取对应的key就可以看到相应的value
.
取出指定时间戳,显示是哪年的第多少天。
1.5 time.mktime
将具体的格式时间转换为时间戳
1.6 time.strftime与time.strptime
time.strftime用于将具体格式时间转换为格式化的字符串时间
通过help查看用法,可以看到%符号后面对应字母所代表的内容,图中红线部分是使用格式。
%Y:年
%m:月
%d:日
%H:小时
%M:分钟
%S:秒
strptime的使用格式
strptime是用来将字符串转为具体的格式时间
strptime是与strftime相反的功能,这里用逗号隔开的两边内容格式要一 一对应,2017对应%Y,10对应%m,这里位置上的联系一定要对应。
strftime使用时间格式默认就是本地时间,可以通过指定其他的时间来输出字符串格式的时间,time.localtime相当于给这个格式赋值
调整格式的位置,输出的字符串时间格式也会随着改变
当前的x相当于2017-10-11 xx:xx:xx,而格式没有与该时间想对应,说明使用strftime在位置上的格式是没有联系的
1.7 time.asctime
用英文的方式进行表示(将元组的格式事件转换为英文时间格式)
1.8 time.ctime
用于将时间戳转换为英文时间格式
2.datetime
datetime.date 获取年月日
datetime.time 获取时分秒
datetime.datetime 获取年月日时分秒
获取现在的时间
显示根据当前时间+3天;显示根据当前时间-3天
前后的小时 时间
3.random模块
3.1 random.random
随机获取浮点数
3.2 random.randint
随机获取指定的整数
3.3 random.randrange
使用randrange和range类似,最后一个数字不算
3.4 random.choice
在不同的数据类型中随机选值
3.5 radom.sample
随机取两个值
3.6 random.unifORM
random.random默认只能取值0-1的浮点数,可以通过random.uniform来指定浮点数范围
3.7 random.shuffle(洗×××功能)
把顺序打乱
3.8 验证码练习
3.8.1使用数字验证
import random
checkcode = ''
for i in range(4): #指定4位验证码的长度
current = random.randint(0,9) #指定随机数字
checkcode+=str(current) #将随机的数字加入到变量中
print (checkcode) #打印随机的验证码
3.8.2使用数字+字母验证
chr65到69 一 一对应了A-Z字母
checkcode = ''
for i in range(4): #循环4次,相当于4位长度的验证码
current = random.randint(0,4) #设定current随机数字与range范围相等
if current == i:
tmp = chr(random.randint(65,90)) #随机匹配:当current等于i时,就随机一个字母
else:
tmp=random.randint(0,9) #当current不等于i时,就随机一个数字
checkcode+=str(tmp) #将tmp产生的数字或字母加入到checkcodee变量中
print (checkcode)
字母+数字的随机验证码
4.OS模块
http://Python.usyiyi.cn/translate/python_278/library/os.html
os模块使用参考网址
os用于调取系统命令
4.1 os.getcwd
获取当前操作目录
4.2 os.chdir
切换操作目录
c:后面是两个\,第一个\是转译符,使用\只能转译后面的一个符号
通过用r来转义
4.3 os.curdir
返回当前目录
一个点'.'表示当前目录
4.4 os.pardir
返回上级目录
两个'..' 两个点表示上级目录
4.5 os.makedirs与 os.removedirs
4.5.1
在D盘先建立a目录,在a目录中建立b目录,以此类推
makedirs可以建立多个目录
4.5.2
在a目录中建立一个文档
可以看到除了D盘和a目录,其他目录都被删除了;这是因为使用os.removedirs是删除空的目录,当前D盘和a目录都是非空
removedirs是递归的删除,只要上一层目录为空就删除,会删掉多个空的目录
4.6 os.mkdir
mkdir也是用于建立目录的,只不过是建立单个目录的
建立多个目录失败
建立单个目录,建立多级目录的话,需要一个一个的去建立
4.7 os.rmdir
将原有的目录删除,重新建立,然后通过rmdir删除,只会删除一个目录,不会删除多个。
4.8 os.listdir
以列表的方式列出当前目录有哪些内容
‘.’表示当前目录
默认也是列出当前目录
列出指定目录内容
4.9 os.remove
删除指定内容
4.10 os.rename
os.rename('oldname','newname') 重命名
4.11 os.stat
获取指定内容属性信息
4.12 os.sep
在windows中路径是用 右斜杠\ 来表示分隔的
在linux中路径是用左斜杠/来表示分隔
os.sep会根据系统的不同,来改变分隔符的,在Windows中是\(其中一个\是转译符),使用os.sep代替\,这样即使在不同的操作系统也能正确的使用对应的分隔符
4.13 os.linesep
换行符是\r\n
4.14 os.environ与os.pathsep
通过environ获取系统的环境变量,以字典格式显示,在Windows中 如果一个key对应多个路径的话是以分好‘;’分隔的,os.pathsep就是对应这个分隔符(在Windows中对应‘;’,在linux中对应‘:’)
4.15 os.name
显示当前系统类型,nt表示Windows
4.16 os.system
用来执行当前系统的命令
编码不同,所以显示乱码
4.17 os.path
4.17.1 os.path.abspath
获取绝对路径(之前在导入模块时使用过,导入不同目录的模块)
4.17.2 os.path.split
以元组的方式显示,将目录和文件分隔开。
4.17.3 os.path.dirname与os.path.basename
一个取目录名,一个结尾的。
4.17.4 os.path.exist
判断路径是否存在
4.17.5 os.path.isabs
判断是否是以根开头的绝对路径
在Windows中每个盘符都是根,在linux中/是根
如果False的话就是相对路径
4.17.6 os.path.isfile与 os.path.isdir
判断是否是一个文件
判断是否是目录
4.17.7 os.path.join
将目录与文件组合并返回
4.17.8 os.path.getatime与 os.path.getmtime
获取文件的最后存取时间,时间格式为时间戳
获取修改时间
5. sys与shutil模块
sys模块没有细讲,请单独翻阅资料
5.1 sys.version
获取当前python的版本信息
5.2 sys.argv
获取相对路径(初始模块文章中讲过)
6. shutil模块
shutil用于copy文件用的
6.1 shutil.copyfileobj
import shutil
f1 = open('test1.txt',encoding='utf-8')
f2 = open('test2.txt','w',encoding='utf-8')
shutil.copyfileobj(f1,f2)
成功的将test1中的内容copy到test2
6.2 shutil.copyfile
shutil.copyfile中已经带有打开文件的代码,所以无需额外再次打开文件了,直接使用即可
6.3 shutil.copymode
将文件的权限拷贝,新文件的用户属主是新用户
6.4 shutil.copystat
只copy了权限
6.5 shutil.copytree与shutil.rmtree
6.6 shutil.make_arvHive
默认在当前操作目录
指定目录
6.7 zipfile、tarfile
import zipfile
压缩
z = zipfile.ZipFile('laxi.zip', 'w')
z.write('a.log')
z.write('data.data')
z.close()
解压
z = zipfile.ZipFile('laxi.zip', 'r')
z.extractall()
z.close()
压缩
import tarfile
tar = tarfile.open('your.tar','w')
tar.add('/Users/wupeiqi/PyCharmProjects/bbs2.log', arcname='bbs2.log')
tar.add('/Users/wupeiqi/PycharmProjects/cmdb.log', arcname='cmdb.log')
tar.close()
解压
tar = tarfile.open('your.tar','r')
tar.extractall() # 可设置解压地址
tar.close()
7. JSON、pickle、shelve
json,用于字符串 和 python数据类型间进行转换
pickle,用于python特有的类型 和 python的数据类型间进行转换
Json模块提供了四个功能:dumps、dump、loads、load
pickle模块提供了四个功能:dumps、dump、loads、load
7.1 json
json之前整理过,可以在不同的语言或系统平台进行数据的转换
只支持部分数据类型
s1={"k1":"v1"}
st=json.dumps(s1)
print(st,type(st))
s='{"k1":"v1"}'
dic=json.loads(s)
print(dic,type(dic))
输出结果为:
{"k1": "v1"} <class 'str'>
{'k1': 'v1'} <class 'dict'>
可以看出json的dumps方法处理数据时会将数据转换为字符类型,loads则会重新还原它的类型。
再来看json的dump和load方法,通过示例来了解:
li=[11,22,33]
li=json.dump(li,open('db','w'))
li=json.load(open('db','r'))
print(li,type(li))
输出结果为:
[11, 22, 33] <class 'list'>
Json模块dumps、loads、load、dump的区别:
load,dump可加载外部文件,处理文件的数据,dumps,loads主要处理内存中的数据
7.2 pickle
pickle之前整理过,只能在python之间数据进行转换(如不同版本)
支持全部数据类型
import pickle
i=[11,22,33]
r=pickle.dumps(li)
print(r)
result=pickle.loads(r)
print(result)
结果为:
b'\x80\x03]q\x00(K\x0bK\x16K!e.'
[11, 22, 33]
pickle的dupms方法会将数据存为pickle特有的数据类型
再看pickle的dump和load方法,通过示例我们来了解:
import pickle
i=[11,22,33]
pickle.dump(i,open('db','wb'))
result=pickle.load(open('db','rb'))
print(result)
结果为:
[11, 22, 33]
需要注意的是dump文件或者load文件是需要使用二进制。
7.3 shelve
shelve是一额简单的数据存储方案,他只有一个函数就是open(),这个函数接收一个参数就是文件名,然后返回一个shelf对象,你可以用他来存储东西,就可以简单的把他当作一个字典,当你存储完毕的时候,就调用close函数来关闭。
f = shelve.open('user.db','wc')
f['baidu'] = 'www.baidu.com'
f['qq'] = 'www.qq.com'
f['360'] = 'www.360.cn'
f.close()
f = shelve.open('user.db','a+')
print(f['baidu'],f['qq'],f['360'])
结果为:
www.baidu.com
www.qq.com
www.360.cn
对shelve序列化数据进行更新操作,通过示例来进行学习:
f=shelve.open('user_db','c')
f["user"]={"数码电器": {"打印机": "3600", "手机": "3800", "电脑": "8000", "照相机": "10000"},
"服装百货": {"方便面": "4", "夹克": "300", "牛仔裤": "288", "王老吉": "6"},
"化妆品": {"韩束": "388", "欧诗漫": "666", "欧莱雅": "888", "百雀羚": "259"},
"汽车":{"帕沙特": "250000", "奇瑞": "100000", "特斯拉": "999999", "宝马X5": "550000"}
}
a=(f["user"])
a.update({"食品":{"猪肉":"12","牛肉":"28","鸡肉":"8","羊肉":"32",}})
f["user"]=a
f.close()
f=shelve.open('user_db','a')
print(f["user"])
8. xml处理模块
xml与json类似,json使用起来更简单,只不过在json没有诞生时,使用的就是xml。
不过现在有一些企业依然使用xml来取xml数据
xml是通过<>节点来区别数据结构的
8.1 xml处理
这是一个xml文件的内容
import xml.etree.ElementTree as ET
tree = ET.parse("xmltest.xml") #要处理xmltest.xml文件
root = tree.getroot()
print(root) #只会打印出内存地址
print(root.tag) #会打印出内存地址对应的内容
将第一行的data给打印出来了
遍历xml文档
for child in root:
print(child.tag, child.attrib)
for i in child:
print(i.tag, i.text,i.attrib)
child.tag是xml文件中的标签名(如:country), child.attrib是属性(如:name="Liechtenstein")
i.tag表示rank(标签名)
i.text表示2 (值)
i.attrib表示updated="yes"> (属性)
只遍历year 节点
for node in root.iter('year'):
print(node.tag, node.text)
8.2 xml修改
import xml.etree.ElementTree as ET
tree = ET.parse("xmltest.xml")
root = tree.getroot()
for node in root.iter('year'): #循环year有关的节点
new_year = int(node.text) + 1 #循环的是字符串,需要转换成数字然后+1(加一年)
node.text = str(new_year) #text表示值,将这个值(20XX)转换为字符串
node.set("updated_by", "Alex") #新增属性
tree.write("xmltest.xml") #将内容写入源文件(xmltest.xml)
可以看到源文件中的year值都加了一年
8.3 删除
删除之前有一个叫Panama的country
for country in root.findall('country'): #查找所有country
rank = int(country.find('rank').text) #查找country下面的rank
if rank > 50: #如果ran中的值大于50就删除当前country
root.remove(country)
tree.write('output.xml')
已经看不到Panama这个country了
8.4 创建
import xml.etree.ElementTree as ET
new_xml = ET.Element("personinfolist") #根节点personinfolist
personinfo = ET.SubElement(new_xml, "personinfo", attrib={"enrolled": "yes"}) #创建new_xml的子节点; personinfo是节点名;attrib是属性
name = ET.SubElement(personinfo, "name") #该节点是personinfo的子节点
name.text = "Alex Li"
age = ET.SubElement(personinfo, "age", attrib={"checked": "no"})
sex = ET.SubElement(personinfo, "sex")
age.text = '56'
personinfo2 = ET.SubElement(new_xml, "personinfo", attrib={"enrolled": "no"})
name = ET.SubElement(personinfo2, "name")
name.text = "Oldboy Ran"
age = ET.SubElement(personinfo2, "age")
age.text = '19'
et = ET.ElementTree(new_xml) # 生成文档对象
et.write("test.xml", encoding="utf-8", xml_declaration=True) #xml_declaration表示生成的格式是xml
ET.dump(new_xml) # 打印生成的格式
可以看到生成的xml文件,只不过默认格式不对,需要手动调整一下。
调整后的文件
9. PyYAML和configparser
9.1 PyYAML
PyYAML是用来做配置文件的
9.2 configparser
configparser 可以用来生成和修改常见配置文件,如:以conf为结尾的配置文件
python3的写法:configparser
python2的写法:ConfigParser
9.2.1 写入
import configparser
config = configparser.ConfigParser() #生成处理对象并赋值
config['DEFAULT']={'ServerAliveInterval':'45',
'Compression':'yes',
'CompressionLevel':'9',
'ForwardX11':'yes'}
config["DEFAULT"] = {'ServerAliveInterval': '45',
'Compression': 'yes',
'CompressionLevel': '9'} #生成配置文件内容,以字典的方式
config['bitbucket.org'] = {}
config['bitbucket.org']['User'] = 'hg' #与上面的结果一样,只是写的方式不同
config['topsecret.server.com'] = {}
config['topsecret.server.com']
config['topsecret.server.com']['Host Port'] = '50022' # mutates the parser
config['topsecret.server.com']['ForwardX11'] = 'no' # same here
config['DEFAULT']['ForwardX11'] = 'yes'
with open('example.ini', 'w') as configfile:
config.write(configfile)
通过python生成的一个配置文件
红色表示节点,图中内容有三个节点
9.2.2 读取
import configparser
conf = configparser.ConfigParser()
conf.read("example.ini")
print(conf.defaults())
使用defaults可以调用example.ini文件中的[DEFAULT]对应的内容,defaults是自带的操作方法
print(conf['bitbucket.org']['user'])
其他的节点只能通过字典的方式来调用
sec = conf.remove_section('bitbucket.org') #删除指定节点
conf.write(open('example.ini', "w")) #写入
10. hashlib
用于加密相关的操作,3.x里代替了md5模块和sha模块,主要提供 SHA1, SHA224, SHA256, SHA384, SHA512 ,MD5 算法
10.1 MD5
import hashlib
m = hashlib.md5() #使用MD5算法
m.update(b'Hello') #b表示bytes类型
print (m.hexdigest()) #使用十六进制打印,hexdigest就表示十六进制格式
m.update(b'Its me')
print (m.hexdigest())
第一个生成的MD5是Hello
第二个生成的MD5是Hello加上Its me
因为MD5值不能翻转,所以通过其他方式确认第二个MD5是否是两个字符串加在一起生成的
可以看到通过m2打印的MD5 值与之前的一样,说明之前的解释没有错。
10.2 sha
m3 = hashlib.sha3_512()
m3.update(b'HelloIts me')
print (m3.hexdigest())
sha512加密长度深,算法复杂度也高,但效率也是相对较低
10.3 hMac
python 还有一个 hmac 模块,它内部对我们创建 key 和 内容 再进行处理然后再加密
散列消息鉴别码,简称HMAC,是一种基于消息鉴别码MAC(Message Authentication Code)的鉴别机制。使用HMAC时,消息通讯的双方,通过验证消息中加入的鉴别密钥K来鉴别消息的真伪;
一般用于网络通信中消息加密,前提是双方先要约定好key,就像接头暗号一样,然后消息发送把用key把消息加密,接收方用key + 消息明文再加密,拿加密后的值 跟 发送者的相对比是否相等,这样就能验证消息的真实性,及发送者的合法性了。
import hmac
h = hmac.new(b'12345',b'qwerasdf') #abc123是key,1234qwer是消息,
print (h.hexdigest())
默认不能用中文,只能用ASCII码(前面有b,必须生成bytes格式,bytes格式要用ASCII)
key必须使用bytes格式,消息可以使用中文,但需要将前面的b去掉,然后并封装新的格式(utf-8)
11. subprodcess
subprodcess是os.system和os.spawn的替代模块
subprocess是Python 2.4中新增的一个模块,它允许你生成新的进程,连接到它们的 input/output/error 管道,并获取它们的返回(状态)码。这个模块的目的在于替换几个旧的模块和方法,如os.system、os.spawn、os.popen、commands.等。subprocess通过子进程来执行外部指令,并通过input/output/error管道,获取子进程的执行的返回信息。
常用方法:
subprocess.call():执行命令,并返回执行状态,其中shell参数为False时,命令需要通过列表的方式传入,当shell为True时,可直接传入命令
(1)
示例如下:
import subprocess
a = subprocess.call(['df','-hT'],shell=False)
print(a)
执行结果:
文件系统 类型 容量 已用 可用 已用% 挂载点
/dev/mapper/Centos-root xfs 22G 9.0G 14G 41% /
devtmpfs devtmpfs 894M 0 894M 0% /dev
tmpfs tmpfs 910M 0 910M 0% /dev/shm
tmpfs tmpfs 910M 19M 892M 3% /run
tmpfs tmpfs 910M 0 910M 0% /sys/fs/cgroup
/dev/sda1 xfs 1014M 233M 782M 23% /boot
tmpfs tmpfs 182M 4.0K 182M 1% /run/user/42
tmpfs tmpfs 182M 48K 182M 1% /run/user/0
0
(2)
subprocess.check_call():用法与subprocess.call()类似,区别是,当返回值不为0时,直接抛出异常
import subprocess
a = subprocess.check_call('ifconfig',shell=True)
print(a)
执行结果:
ens32: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 192.168.200.150 netmask 255.255.255.0 broadcast 192.168.200.255
inet6 fe80::1715:d111:c3D7:a081 prefixlen 64 scopeid 0x20<link>
ether 00:0c:29:bd:d1:99 txqueuelen 1000 (Ethernet)
RX packets 757729 bytes 831629447 (793.1 MiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 207676 bytes 58597215 (55.8 MiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
(3)
import subprocess
a = subprocess.check_call('abcd',shell=True)
print(a)
执行结果:
/bin/sh: abcd: 未找到命令
Traceback (most recent call last):
File "/tmp/pycharm_project_538/codes_practice/aa1/A4.py", line 2, in <module>
a = subprocess.check_call('abcd',shell=True)
File "/usr/local/lib/python3.6/subprocess.py", line 291, in check_call
raise CalledProcessError(retcode, cmd)
subprocess.CalledProcessError: Command 'abcd' returned non-zero exit status 127.
(4)
subprocess.check_output():用法与上面两个方法类似,区别是,如果当返回值为0时,直接返回输出结果,如果返回值不为0,直接抛出异常。需要说明的是,该方法在python3.x中才有。
(5)
subprocess.Popen():
在一些复杂场景中,我们需要将一个进程的执行输出作为另一个进程的输入。在另一些场景中,我们需要先进入到某个输入环境,然后再执行一系列的指令等。这个时候我们就需要使用到suprocess的Popen()方法。该方法有以下参数:
args:shell命令,可以是字符串,或者序列类型,如list,tuple。
bufsize:缓冲区大小,可不用关心
stdin,stdout,stderr:分别表示程序的标准输入,标准输出及标准错误
shell:与上面方法中用法相同
cwd:用于设置子进程的当前目录
env:用于指定子进程的环境变量。如果env=None,则默认从父进程继承环境变量
universal_newlines:不同系统的的换行符不同,当该参数设定为true时,则表示使用\n作为换行符
(5.1)
import subprocess
obj = subprocess.Popen(["python"], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
obj.stdin.write('print(1) \n')
obj.stdin.write('print(2) \n')
obj.stdin.write('print(3) \n')
obj.stdin.close()
cmd_out = obj.stdout.read()
obj.stdout.close()
cmd_error = obj.stderr.read()
obj.stderr.close()
print (cmd_out)
print (cmd_error)
(5.2)
Popen.communicate(input=None)
与子进程进行交互。向stdin发送数据,或从stdout和stderr中读取数据。可选参数input指定发送到子进程的参数。 Communicate()返回一个元组:(stdoutdata, stderrdata)。注意:如果希望通过进程的stdin向其发送数据,在创建Popen对象的时候,参数stdin必须被设置为PIPE。同样,如 果希望从stdout和stderr获取数据,必须将stdout和stderr设置为PIPE。
使用如下方法:
import subprocess
obj = subprocess.Popen(["python"], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
obj.stdin.write('print(1) \n')
obj.stdin.write('print(2) \n')
obj.stdin.write('print(3) \n')
obj.stdin.close()
out_error_list = obj.communicate()
print (out_error_list)
(5.3)
将一个子进程的输出,作为另一个子进程的输入:
import subprocess
child1 = subprocess.Popen(["cat","/etc/passwd"], stdout=subprocess.PIPE)
child2 = subprocess.Popen(["grep","0:0"],stdin=child1.stdout, stdout=subprocess.PIPE)
out = child2.communicate()
(5.4)
import subprocess
child = subprocess.Popen('sleep 60',shell=True,stdout=subprocess.PIPE)
Popen.poll()
用于检查子进程是否已经结束。设置并返回returncode属性。
Popen.wait()
等待子进程结束。设置并返回returncode属性。
Popen.communicate(input=None)
与子进程进行交互。向stdin发送数据,或从stdout和stderr中读取数据。可选参数input指定发送到子进程的参数。 Communicate()返回一个元组:(stdoutdata, stderrdata)。注意:如果希望通过进程的stdin向其发送数据,在创建Popen对象的时候,参数stdin必须被设置为PIPE。同样,如 果希望从stdout和stderr获取数据,必须将stdout和stderr设置为PIPE。
Popen.send_signal(signal)
向子进程发送信号。
Popen.terminate()
停止(stop)子进程。在windows平台下,该方法将调用Windows api TerminateProcess()来结束子进程。
Popen.kill()
杀死子进程。
Popen.stdin
如果在创建Popen对象是,参数stdin被设置为PIPE,Popen.stdin将返回一个文件对象用于策子进程发送指令。否则返回None。
Popen.stdout
如果在创建Popen对象是,参数stdout被设置为PIPE,Popen.stdout将返回一个文件对象用于策子进程发送指令。否则返回 None。
Popen.stderr
如果在创建Popen对象是,参数stdout被设置为PIPE,Popen.stdout将返回一个文件对象用于策子进程发送指令。否则返回 None。
Popen.pid
获取子进程的进程ID。
Popen.returncode
获取进程的返回值。如果进程还没有结束,返回None。
12. logging
12.1 日志级别信息输出
import logging
logging.debug('test debug')
logging.info('test info')
logging.warning('the warning info')
logging.error('the error info')
logging.critical('the critical info')
logging.basicConfig(filename='app.log',level=logging.DEBUG)
这条代码一定要放在下面代码的上面才会生效。
这里日志级别是DEBUG,意思就是将DEBUG以及比其高的级别的日志都进行输出
可以看到新增代码后,就不在pycharm中输出日志信息了
根据指定的app.log文件,将信息输出到文件中。
在执行一遍代码,日志信息就会增加到app.log文件中(不会覆盖)
将WARNING级别以及比其高的级别日志信息输出
12.3 添加日志格式
logging.basicConfig(filename='app.log',level=logging.WARNING,format='%(asctime)s %(message)s',datefmt='%m/%d/%Y %I:%M:%S %p')
format定义日志格式内容; datefmt定义时间格式(月/日/年 时分秒 %p表示上午或下午)
定义日志格式,让其显示日志级别
显示输出的文件名
因为格式原因输出有乱码,实际输出的应该是logging模块.py
使用%(lineno)d可以显示输出文档的行号
可以看到该日志信息是通过哪个文档的哪一行输出的。
%(funcName)s显示生成日志的函数名称
可以看到app_run;不是通过函数则为空(<module>)
12.4 logging模块涉及四个主要类
logger提供了应用程序可以直接使用的接口
handler将(logger创建的)日志记录发送到合适的目的输出(输出到屏幕、文件、邮件等);
filter提供了细度设备来决定输出哪条日志记录;
formatter决定日志记录的最终输出格式。
12.4.1 logger
logger相当于一个接口,发送日志都需要调用logger。
每个程序在输出信息之前都要获得一个Logger。Logger通常对应了程序的模块名,比如聊天工具的图形界面模块可以这样获得它的Logger:
LOG=logging.getLogger(”chat.gui”) #返回一个logger对象,如果没有指定name,返回root logger。只要name相同,返回的logger对象都是同一个而且只有一个,即name和logger对象是一一对应的。这意味着,无需把logger对象在各个模块中传递。只要知道name,就能得到同一个logger对象。
通常logger的名字我们对应模块名,如聊天模块、数据库模块、验证模块等。
而核心模块可以这样:
LOG=logging.getLogger(”chat.kernel”)
Logger.setLevel(lel): #指定最低的日志级别,低于lel的级别将被忽略。debug是最低的内置级别,critical为最高
Logger.addFilter(filt)、Logger.removeFilter(filt): #添加或删除指定的filter (这个很少用到)
Logger.addHandler(hdlr)、Logger.removeHandler(hdlr): #增加或删除指定的handler
Logger.debug()、Logger.info()、Logger.warning()、Logger.error()、Logger.critical(): #可以设置的日志级别
12.4.2 handler
handler对象负责发送相关的信息到指定目的地。Python的日志系统有多种Handler可以使用。有些Handler可以把信息输出到控制台,有些Logger可以把信息输出到文件,还有些 Handler可以把信息发送到网络上。如果觉得不够用,还可以编写自己的Handler。可以通过addHandler()方法添加多个多handler
Handler.setLevel(lel): #指定被处理的信息级别,低于lel级别的信息将被忽略
Handler.setFormatter(): #给这个handler选择一个格式
Handler.addFilter(filt)、Handler.removeFilter(filt): #新增或删除一个filter对象
每个Logger可以附加多个Handler。接下来我们就来介绍一些常用的Handler:
1) logging.StreamHandler(输出到屏幕)
使用这个Handler可以向类似与sys.stdout或者sys.stderr的任何文件对象(file object)输出信息。它的构造函数是:
StreamHandler([strm])
其中strm参数是一个文件对象。默认是sys.stderr
2) logging.FileHandler(输出到文件)
和StreamHandler类似,用于向一个文件输出日志信息。不过FileHandler会帮你打开这个文件。它的构造函数是:
FileHandler(filename[,mode])
filename是文件名,必须指定一个文件名。
mode是文件的打开方式。参见Python内置函数open()的用法。默认是’a',即添加到文件末尾。
3) logging.handlers.RotatingFileHandler
这个Handler类似于上面的FileHandler,但是它可以管理文件大小。当文件达到一定大小之后,它会自动将当前日志文件改名,然后创建 一个新的同名日志文件继续输出。比如日志文件是chat.log。当chat.log达到指定的大小之后,RotatingFileHandler自动把 文件改名为chat.log.1。不过,如果chat.log.1已经存在,会先把chat.log.1重命名为chat.log.2。。。最后重新创建 chat.log,继续输出日志信息。它的构造函数是:
RotatingFileHandler( filename[, mode[, maxBytes[, backupCount]]])
其中filename和mode两个参数和FileHandler一样。
maxBytes用于指定日志文件的最大文件大小。如果maxBytes为0,意味着日志文件可以无限大,这时上面描述的重命名过程就不会发生。
backupCount用于指定保留的备份文件的个数。比如,如果指定为2,当上面描述的重命名过程发生时,原有的chat.log.2并不会被更名,而是被删除。
4) logging.handlers.TimedRotatingFileHandler
这个Handler和RotatingFileHandler类似,不过,它没有通过判断文件大小来决定何时重新创建日志文件,而是间隔一定时间就 自动创建新的日志文件。重命名的过程与RotatingFileHandler类似,不过新的文件不是附加数字,而是当前时间。它的构造函数是:
TimedRotatingFileHandler( filename [,when [,interval [,backupCount]]])
其中filename参数和backupCount参数和RotatingFileHandler具有相同的意义。
interval是时间间隔。
when参数是一个字符串。表示时间间隔的单位,不区分大小写。它有以下取值:
S 秒
M 分
H 小时
D 天
W 每星期(interval==0时代表星期一)
midnight 每天凌晨
12.4.2.1输出到多个目的
import logging
logger = logging.getLogger('TEST-LOG') #获取接口对象
logger.setLevel(logging.DEBUG) #定义记录告警信息的最低等级
ch = logging.StreamHandler() #定义Handler,可以输出到屏幕
ch.setLevel(logging.WARNING) #定义输出到屏幕的告警级别
fh = logging.FileHandler('access.log',encoding='utf-8') #定义Handler输出到信息的文件名称
fh.setLevel(logging.ERROR) #定义输出到文件的告警级别
ch_formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') #定义Handler输出到屏幕的格式
fh_formatter = logging.Formatter('%(asctime)s - %(process)d %(filename)s:%(lineno)d') #定义Handler输出到文件的格式
ch.setFormatter(ch_formatter) #关联Handler输出到屏幕的格式
fh.setFormatter(fh_formatter) #关联Handler输出到文件的格式
logger.addHandler(fh) #增加被输出的内容,与logger接口对象做关联
logger.addHandler(ch) #增加被输出的内容,与logger接口对象做关联
#屏幕和文件中都可以被输出
logger.warning('aaaa') #定义告警级别和信息
logger.error('bbbb') #定义告警级别和信息
输出到屏幕的告警信息,因为定义的最低告警级别是warning,所以两个级别的信息都可以看到
输出到文件的告警信息,因为定义的级别是error,所以比error低的告警信息warning信息是看不到的
12.4.2.2 按大小自动截断
import logging
from logging import handlers #需要单独import handlers这个函数
logger = logging.getLogger('TEST')
log_file = "test-log.log"
fh = handlers.RotatingFileHandler(filename=log_file,maxBytes=10,backupCount=3,encoding='utf-8')
#文件名为log_file,每个文件最大存储10字节,最多保留3个备份文件。
formatter = logging.Formatter('%(asctime)s %(module)s:%(lineno)d %(message)s')
fh.setFormatter(formatter)
logger.addHandler(fh)
logger.warning("test1")
logger.warning("test2")
logger.warning("test3")
logger.warning("test4")
logger.warning("test5")
logger.warning("test6")
可以看到自动截断,只保留了3个备份文件,当前主文件的内容就是最后存储的信息'test6'
log.1是最接近主文件的内容的,所以是'test5'
log.3文件存储的是最旧的内容,因为只能每个文件最大10字节,且有3个备份文件的限制,之前的'test1'和'test2'都被删除了。
12.4.2.3 按时间自动截断
fh = handlers.TimedRotatingFileHandler(filename=log_file,when="S",interval=5,backupCount=3)
import logging
from logging import handlers #需要单独import handlers这个函数
import time
logger = logging.getLogger('TEST')
log_file = "test-log.log"
fh = handlers.TimedRotatingFileHandler(filename=log_file,when="S",interval=5,backupCount=3,encoding='utf-8')
#使用handlers.TimedRotatingFileHandler,S表示秒,5就是每隔5秒
formatter = logging.Formatter('%(asctime)s %(module)s:%(lineno)d %(message)s')
fh.setFormatter(formatter)
logger.addHandler(fh)
logger.warning("test1")
time.sleep(2)
logger.warning("test2")
time.sleep(2)
logger.warning("test3")
logger.warning("test4")
time.sleep(2)
logger.warning("test5")
logger.warning("test6")
从第5秒开始截断的
13. re正则表达式模块
13.1 函数语法:
re.match(pattern,string, flags=0)
匹配成功re.match方法返回一个匹配的对象,否则返回None。
我们可以使用group(num) 或 groups() 匹配对象函数来获取匹配表达式。
13.2 re.match函数
函数参数说明:
pattern 匹配的正则表达式
string 要匹配的字符串。
flags 标志位,用于控制正则表达式的匹配方式,如:是否区分,多行匹配等等。
13.2.1 举例1:
re.match 尝试从字符串的起始位置匹配一个模式,如果不是起始位置匹配成功的话,match()就返回none。
import re
print(re.match('www', 'www.Google.com'))
print(re.match('www', 'www.google.com').span())
print(re.match('google', 'www.google.com'))
括号中第一个'www'是正则表达式,相当于匹配的规则; 后面是要匹配的字符串内容。
第一个结果可以看到从起始位置匹配到了'www'
第二个结果来输出匹配到内容的下标位置
第三个结果是none,这是因为在www.google.com中不是以google为起始位置的,所以匹配不到。
13.2.2 举例:
import re
line = "Cats are smarter than dogs"
matchObj = re.match( r'(.*) are (.*?) .*', line)
#将line这个变量作为一个需要匹配的内容;
#这里正则表达式通过()分了两个部分,可以用group来表达,在are之前的(.*)是一部分,在are之后的(.*?) 一个部分,如果去掉的话匹配结果就不同了。
每一个()表示一个分组
if matchObj:
print ("matchObj.group() : ", matchObj.group()) #匹配所有()和非()表达式中的内容
print ("matchObj.group(1) : ", matchObj.group(1)) #匹配第一个()中的表达式内容
print ("matchObj.group(2) : ", matchObj.group(2)) #匹配第二个()中的表达式内容
print ("matchObj.group(3) : ", matchObj.groups()) #匹配所有()中的表达式美容,并以元组的形式显示
else:
print ("No match!!")
13.3 正则表达式修饰符 - 可选标志
正则表达式可以包含一些可选标志修饰符来控制匹配的模式。修饰符被指定为一个可选的标志。多个标志可以通过按位 OR(|) 它们来指定。如 re.I | re.M 被设置成 I 和 M 标志:
13.4 正则表达式模式
模式字符串使用特殊的语法来表示一个正则表达式:
字母和数字表示他们自身。一个正则表达式模式中的字母和数字匹配同样的字符串。
多数字母和数字前加一个反斜杠时会拥有不同的含义。
标点符号只有被转义时才匹配自身,否则它们表示特殊的含义。
反斜杠本身需要使用反斜杠转义。
由于正则表达式通常都包含反斜杠,所以你最好使用原始字符串来表示它们。模式元素(如 r'/t',等价于'//t')匹配相应的特殊字符。
下表列出了正则表达式模式语法中的特殊元素。如果你使用模式的同时提供了可选的标志参数,某些模式元素的含义会改变。
13.5 正则表达式实例
13.6 使用模式举例
- 使用:'.'
line = 'www.google.com'
rule = re.match(r'.',line)
print (rule)
print (rule.group())
使用一个'.'表达除了\n 外的任意一个字符(字母、数字、特殊字符),可以看到职匹配了第一个w
不使用group来表达的话会多现实一些参数,比如span表达了第一个w所在下标的位置范围
- 使用:'.+'
line = 'www.google.com'
rule = re.match(r'.+',line)
'.+'通过'+'匹配了0个或多个'.'
- 使用:'w','w+'
rule1 = re.match(r'w',line) #匹配一个字母
rule2 = re.match(r'w+',line) #匹配1或多个字母
rule3 = re.match(r'w{2}',line) #匹配2个字母
rule4 = re.match(r'w{1,3}',line) #匹配1到3个字母(至少1个,最多3个)
print (rule1.group())
print (rule2.group())
print (rule3.group())
print (rule4.group())
匹配了字母,遇见'.'后不符合表达式(不属于字母),所以连带'.'后面的所有内容也都不匹配了。
rule5 = re.match(r'w+|.+',line)
rule6 = re.match(r'.+|w+',line)
通过|来表示或的意思,但是在匹配的时候,只要前面的规则匹配到了,后面就不在匹配了,所以可以看到匹配的结果不同。
- 使用:‘search’
re.search('www','www.google.com').group() #注意匹配www时是没有使用r或\转义的,所以匹配的就是www字符本身
re.search('google','www.google.com').group()
re.match只匹配字符串的开始,如果字符串开始不符合正则表达式,则匹配失败,函数返回None;而re.search匹配整个字符串,直到找到一个匹配。
- 使用:‘d’
re.search('(\d{3})(\d{4})','123456789123456789').groups()
匹配数字,因为有两个(),所以在元组中分为两个元素显示
使用:‘^,$,Z’
通过^匹配以数字开头的,通过$匹配以数字结尾的,第一个报错是因为匹配的内容不是数字结尾,另一个匹配则是以数字为结尾所以不会报错。
Z与$是一个意思
- 列表项
rule = re.search('\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}','192.168.1.1').group()
print (rule)
rule = re.search('(\d{1,3}\.){3}\d{1,3}','192.168.1.1').group() #稍微优化
print (rule)
rule = re.search('([0-2]?[0-9]?[0-9]+\.){3}[0-2]?[0-9]?[0-9]','192.168.1.1').group()
print (rule)
以上都不是合法的IP地址写法
- 匹配:合法IP地址
rule = re.search('^((25[0-5]|2[0-4]\d|[1]?\d?\d)\.){3}(25[0-5]|2[0-4]\d|[1]?\d?\d)$','255.168.1.255').group()
print (rule)
rule = re.search('^((25[0-5]|2[0-4]\d|[1]?\d?\d)\.){3}(25[0-5]|2[0-4]\d|[1]?\d?\d)$','256.168.1.255').group() #第一个IP被协成256,这是不合法的
print (rule)
可以看到报错
- 使用:'re.findall'
rule1 = re.search('\d+','ab13aa22cc334bb44adsf234656').group()
rule2 = re.findall('\d+','ab13aa22cc334bb44adsf234656') #这里不需要group
print (rule1)
print (rule2)
可以看到search只能寻找其中一个,而findall可以寻找所有。
rule3= re.findall('\D+','ab13aa22cc334bb44adsf234656')
print (rule3)
\D表示非数字
-
使用:'re.split'
rule1 = re.split('\d+','ab13aa22cc334bb44adsf234656') print (rule1)
- 使用re.split分隔成列表显示
可以看到与findall类似,但是split后面因为有数字所以就分隔了一个空
rule1 = re.split('\d+','ab13aa22cc334bb44adsf234656dd') #最后面加个dd字符串
print (rule1)
使用re.split分隔成列表显示
可以看到与findall类似,但是split后面因为有数字所以就分隔了一个空
rule1 = re.split('\d+','ab13aa22cc334bb44adsf234656dd') #最后面加个dd字符串
print (rule1)
会将dd进行分隔
- 使用:re.sub
rule = re.sub('\d+','|','ab13aa22cc334bb44adsf234656dd')
print (rule)
使用re.sub进行替换,将数字替换成 |
rule = re.sub('\d+','XXX','ab13aa22cc334bb44adsf234656dd',count=2)
print (rule)
count是替换几次
- flags
rule = re.search('a+','AAAaaa').group() print (rule)
只能匹配到小写的a
rule = re.search('a+','AAAaaa',re.I).group()
print (rule)
使用falgs中的re.I可以忽略大小写
相关文章