常用模块

常用模块


常用模块

1. time、datatime模块(时间格式的转换,时间的运算)

2. random模块(随机模块

3. os模块

4. sys模块

5. shutil模块

6. json、pickle、shelve

7. xml模块

8. configparser模块

9. hashlib模块

10. subprocess模块

11. logging模块

12. re模块


time模块

``` python
import time
# 时间戳
a = time.time()  # 时间戳,系统识别的时间
print(a)  # ==>1530340071.1975565


# 时间对象/结构化时间
b = time.localtime()  # 生成一个结构化时间,参数可以加指定的时间戳时间,默认为北京当前时间
print(b)  # time.struct_time(tm_year=2018, tm_mon=6, tm_mday=30, tm_hour=14, tm_min=29,tm_sec=36, tm_wday=5, tm_yday=181, tm_isdst=0)

b1 = time.gmtime() # 生成格林威治时间对象(结构化时间),也可以指定参数,时间戳时间
print(b1)  # time.struct_time(tm_year=2018, tm_mon=6, tm_mday=30, tm_hour=6, tm_min=35, tm_sec=17, tm_wday=5, tm_yday=181, tm_isdst=0)


# 结构化时间转换成字符串时间,指定时间格式
c = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime())  # 参数为时间格式,结构化时间
print(c)  # ==>2018-06-30 14:55:00


# 结构化时间转换成字符串时间,默认格式
s = time.asctime()  # 参数为结构化时间,默认为time.localtime()
print(s)  # ==>Sat Jun 30 14:42:31 2018 

# 将时间戳时间转换成字符串时间
d = time.ctime()  # 参数为一个时间戳时间(小数秒),默认为time.time()
print(d)  # ==>Sat Jun 30 14:42:31 2018

# 将结构化时间转换成时间戳
f = time.mktime(b)  # 参数为结构化时间
print(f)  # ==>1530342514.0

# 将字符串时间转换成结构化时间
h = time.strptime(c, '%Y-%m-%d %H:%M:%S')  # 参数为字符串时间,字符串时间的格式
print(h)  # ==>time.struct_time(tm_year=2018, tm_mon=6, tm_mday=30, tm_hour=15, tm_min=14, tm_sec=30, tm_wday=5, tm_yday=181, tm_isdst=-1)


time.sleep(secs)
(线程)推迟指定的时间运行。单位为秒。

结构化时间的9个参数:

索引(Index) 属性(Attribute) 值(Values)
0 tm_year(年) 比如2011
1 tm_mon(月) 1 - 12
2 tm_mday(日) 1 - 31
3 tm_hour(时) 0 - 23
4 tm_min(分) 0 - 59
5 tm_sec(秒) 0 - 60
6 tm_wday(weekday) 0 - 6(0表示周一)
7 tm_yday(一年中的第几天) 1 - 366
8 tm_isdst(是否是夏令时) 默认为0

格式化字符串时间:

%y 两位数的年份表示(00-99)
%Y 四位数的年份表示(000-9999)
%m 月份(01-12)
%d 月内中的一天(0-31)
%H 24小时制小时数(0-23)
%I 12小时制小时数(01-12)
%M 分钟数(00=59)
%S 秒(00-59)
%a 本地简化星期名称
%A 本地完整星期名称
%b 本地简化的月份名称
%B 本地完整的月份名称
%c 本地相应的日期表示和时间表示
%j 年内的一天(001-366)
%p 本地A.M.或P.M.的等价符
%U 一年中的星期数(00-53)星期天为星期的开始
%w 星期(0-6),星期天为星期的开始
%W 一年中的星期数(00-53)星期一为星期的开始
%x 本地相应的日期表示
%X 本地相应的时间表示
%Z 当前时区的名称
%% %号本身
enter description here



datetime模块

import datetime

a = datetime.datetime.now()  # 获取当前时间
print(a)  # ==>2018-06-28 19:13:15.767451

# 字符串时间
b = datetime.date.fromtimestamp(time.time())
print(b)  # ==>2018-06-28 丢失小时、分钟、秒信息

# 结构化时间/时间对象
c = b.timetuple()  # 得到一个时间对象
print(c)  # ==>time.struct_time(tm_year=2018, tm_mon=6, tm_mday=28, tm_hour=0, 
#  tm_min=0, tm_sec=0, tm_wday=3, tm_yday=179, tm_isdst=-1)

# 时间运算,可以加减
d = datetime.timedelta(days=1, weeks=1, hours=1, minutes=1, seconds=10,)  # 不能是months以上 
f = a - d  # 时间的运算,可以加减
print(f)  # ==>2018-06-20 18:19:31.353533

# 修改时间
g = a.replace(year=2018, month=11, day=21, minute=26, second=50)  # 指定时间,修改时间
print(g)  # ==>2018-11-21 09:26:50.571991


random模块

作用:生成随机字符

# 打乱列表顺序 shuffle

>>> 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

a = random.randint(1, 5)  # 生成随机数,包括5
print(a)  # ==>5

b = random.randrange(1, 5)  # 生成随机数,不包括5
print(b)  # ==>4

c = random.choice('abcdef')  # 生成随机字符
print(c)  # ==>c

d = random.choices('abcdef')  # 生成随机字符,列表形式
print(d)  # ==>['b']

f = random.sample(range(1, 5), 4)  # 生成指定个数的随机数或字符的列表
f1 = random.sample('abcdef', 4)
print(f, f1)  # ==>[1, 2, 4, 3] ['c', 'b', 'a', 'f']

# 生成随机字符串
import string
g = ''.join(random.sample(string.ascii_lowercase + string.digits, 6))
print(g)  # ==>bpu8o2

# 洗牌
h = list(range(1, 10))
print(h)  # ==>[1, 2, 3, 4, 5, 6, 7, 8, 9]
random.shuffle(h)  # 没有返回值,只是做了打乱顺序的操作
print(h)  # ==>[9, 7, 4, 3, 1, 2, 8, 6, 5]



os模块

作用:提供程序与操作系统交互的功能

不带path的命令

os.getcwd() 获取当前工作目录,即当前python脚本工作的目录路径
>>> import os
>>> print(os.getcwd())
C:UsersAdministrator

os.chdir("dirname")  改变当前脚本工作目录;相当于shell下cd

os.curdir  返回当前目录: ('.')

os.pardir  获取当前目录的父目录字符串名:
print(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下为"	
",Linux下为"
"

os.pathsep    输出用于分割文件路径的字符串 win下为;,Linux下为:

os.name    输出字符串指示当前使用平台。win->'nt'; Linux->'posix'
os.system("bash command")  运行shell命令,直接显示
os.popen("bash command).read()  运行shell命令,获取执行结果
os.environ  获取系统环境变量

带path的命令

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.splitext()  分离扩展名      e.g  os.path.splitext('/usr/local/test.py')    结果:('/usr/local/test', '.py')

os.path.getatime(path)  返回path所指向的文件或者目录的最后访问时间

os.path.getmtime(path)  返回path所指向的文件或者目录的最后修改时间

os.path.getsize(path) 返回path的大小

enter description here
enter description here

编程中的应用

path2 = os.path.join(os.path.dirname(os.path.dirname(__file__)), 'log', 'transaction.log') 
# 同个包下输出到另一个文件夹下的文件中


sys模块

作用:sys模块是与python解释器交互的一个接口

sys.argv           命令行参数List,第一个元素是程序本身路径

sys.exit(n)        退出程序,正常退出时exit(0)

sys.version        获取Python解释程序的版本信息

sys.maxint         最大的Int值

sys.path           返回模块的搜索路径,初始化时使用PYTHONPATH环境变量的值

sys.platform       返回操作系统平台名称

sys.stdout.write('please:')  #标准输出 , 引出进度条的例子, 注,在py3上不行,可以用print代替

val = sys.stdin.readline()[:-1] #标准输入
sys.getrecursionlimit() #获取最大递归层数
sys.setrecursionlimit(1200) #设置最大递归层数
sys.getdefaultencoding()  #获取解释器默认编码
sys.getfilesystemencoding  #获取内存数据存到文件里的默认编码


shutil模块

作用:高级的文件、文件夹、压缩包 处理模块

shutil.copyfileobj(fsrc, fdst[, length])
将文件内容拷贝到另一个文件中

import shutil
shutil.copyfileobj(open('old.xml','r'), open('new.xml', 'w'))
shutil.copyfile(src, dst)
拷贝文件

shutil.copyfile('f1.log', 'f2.log') #目标文件无需存在
shutil.copymode(src, dst)
仅拷贝权限。内容、组、用户均不变

shutil.copymode('f1.log', 'f2.log') #目标文件必须存在
shutil.copystat(src, dst)
仅拷贝状态的信息,包括:mode bits, atime, mtime, flags

shutil.copystat('f1.log', 'f2.log') #目标文件必须存在
shutil.copy(src, dst)
拷贝文件和权限

import shutil
shutil.copy('f1.log', 'f2.log')
shutil.copy2(src, dst)
拷贝文件和状态信息

import shutil
shutil.copy2('f1.log', 'f2.log')
shutil.ignore_patterns(*patterns)
shutil.copytree(src, dst, symlinks=False, ignore=None)
递归的去拷贝文件夹

import shutil
shutil.copytree('folder1', 'folder2', ignore=shutil.ignore_patterns('*.pyc', 'tmp*')) #目标目录不能存在,注意对folder2目录父级目录要有可写权限,ignore的意思是排除
shutil.rmtree(path[, ignore_errors[, onerror]])
递归的去删除文件

import shutil
shutil.rmtree('folder1')
shutil.move(src, dst)
递归的去移动文件,它类似mv命令,其实就是重命名。

import shutil
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对象
#将 /data 下的文件打包放置当前程序目录
import shutil
ret = shutil.make_archive("data_bak", 'gztar', root_dir='/data')

#将 /data下的文件打包放置 /tmp/目录
import shutil
ret = shutil.make_archive("/tmp/data_bak", 'gztar', root_dir='/data')
shutil 对压缩包的处理是调用 ZipFile 和 TarFile 两个模块来进行的,详细:
zipfile压缩&解压缩

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(path='.')
z.close()
tarfile压缩&解压缩

import tarfile

# 压缩
>>> t=tarfile.open('/tmp/egon.tar','w')
>>> t.add('/test1/a.py',arcname='a.bak')
>>> t.add('/test1/b.py',arcname='b.bak')
>>> t.close()

# 解压
>>> t=tarfile.open('/tmp/egon.tar','r')
>>> t.extractall('/egon')
>>> t.close()


序列化模块

定义:序列化是指把内存里的数据类型转变成字符串,以使其能存储到硬盘或通过网络传输到远程,因为硬盘或网络传输时只能接受bytes类型。

序列化的目的

1、以某种存储形式使自定义对象持久化;
2、将对象从一个地方传递到另一个地方。
3、使程序更具维护性。

用于序列化的两个模块

json,用于字符串 和 python数据类型间进行转换
pickle,用于python特有的类型bytes 和 python的数据类型间进行转换

Json模块提供了四个功能:dumps、dump、loads、load
pickle模块提供了四个功能:dumps、dump、loads、load

json模块

import json

# dumps和loads,在内存中对数据进行序列化和反序列化
l = (1, 2, 3, 4, 5)
ret1 = json.dumps(l)  # 序列化,将一个元组序列化成字符串
print(ret1, type(ret1))  # ==>[1, 2, 3, 4, 5] <class 'str'>

ret2 = json.loads(ret1)  # 反序列化,把字符串类型的序列化结果变成原来的类型 ps:元组经过序列化再反序列化会变成列表
print(ret2, type(ret2))  # ==>[1, 2, 3, 4, 5] <class 'list'>


# dump和load,直接进行文件存取间的序列化
dic = {'k1': '中国', 'k2': 'v2', 'k3': 'v3'}
f = open('fff', 'w', encoding='utf-8')
json.dump(dic, f, ensure_ascii=False)  # 将dic序列化保存到文件中
f.close()  # f:{"k1": "中国", "k2": "v2", "k3": "v3"}

f = open('fff', encoding='utf-8')  
data = json.load(f)  # 将文件中的内容反序列化
f.close()
print(data, type(data))  # ==>{'k1': '中国', 'k2': 'v2', 'k3': 'v3'} <class 'dict'>

PS:可以多次dump到文件,但是不能多次load到内存中。


pickel模块

import pickle

# dumps和loads,在内存中对数据进行序列化和反序列化
l = (1, 2, 3, 4)
ret1 = pickle.dumps(l)  # 序列化,将一个元组序列化成bytes类型
print(ret1, type(ret1))  # ==>b'x80x03(Kx01Kx02Kx03Kx04tqx00.' <class 'bytes'>

ret2 = pickle.loads(ret1)  # 反序列化,把字符串类型的序列化结果变成原来的类型
print(ret2, type(ret2))  # ==>(1, 2, 3, 4) <class 'tuple'>



# dump和load,直接进行文件存取间的序列化

dic = {'k1': '中国', 'k2': 'v2', 'k3': 'v3'}
f = open('fff', 'wb')  # pickle是将bytes类型写入文件中,所以用‘wb'
pickle.dump(dic, f)  # 将dic序列化保存到文件中
f.close()  # f:pickle特有的格式

f = open('fff', 'rb')  # 要用rb的模式
data = pickle.load(f)  # 将文件中的内容反序列化
f.close()
print(data, type(data))  # ==>{'k1': '中国', 'k2': 'v2', 'k3': 'v3'} <class 'dict'>

ps:pickle模块支持多次dump,和同次数的load。
元组类型经过序列化和反序列化的过程中不会变成列表。

json vs pickle:

JSON:

优点:跨语言、体积小

缺点:只能支持intstrlist upledict

Pickle:

优点:专为python设计,支持python所有的数据类型

缺点:只能在python中使用,存储数据占空间大


shelve模块

shelve模块是一个简单的k,v将内存数据通过文件持久化的模块,可以持久化任何pickle可支持的python数据格式

import shelve
f = shelve.open('fff')  # 打开一个文件

names = ["alex", "rain", "test"]
info = {'name': 'alex', 'age': 22}

f["names"] = names  # key-value的结构,可以直接进行修改,删除操作
f['info_dic'] = info  # 存数据

f.close()


import shelve

d = shelve.open('shelve_test')  # 打开一个文件

print(d['names'])   # 取数据
print(d['info_dic'])
#del d['test'] #还可以删除

shelve:是对pickle的封装,支持所有的python数据类型,支持多次操作,能够修改、删除里面的内容


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

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)
    for i in child:
        print(i.tag,i.text)

#只遍历year 节点
for node in root.iter('year'):
    print(node.tag,node.text)

修改和删除xml文档内容

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")

tree.write("xmltest.xml")


#删除node
for country in root.findall('country'):
   rank = int(country.find('rank').text)
   if rank > 50:
     root.remove(country)

tree.write('output.xml')

创建xml文档

import xml.etree.ElementTree as ET


new_xml = ET.Element("namelist")
name = ET.SubElement(new_xml,"name",attrib={"enrolled":"yes"})
age = ET.SubElement(name,"age",attrib={"checked":"no"})
sex = ET.SubElement(name,"sex")
sex.text = '33'
name2 = ET.SubElement(new_xml,"name",attrib={"enrolled":"no"})
age = ET.SubElement(name2,"age")
age.text = '19'

et = ET.ElementTree(new_xml) #生成文档对象
et.write("test.xml", encoding="utf-8",xml_declaration=True)

ET.dump(new_xml) #打印生成的格式


configparser模块

作用:用于生成和修改常见配置文档

常见配置文件格式如下

[DEFAULT]
ServerAliveInterval = 45   
Compression = yes
CompressionLevel = 9
ForwardX11 = yes

[bitbucket.org]
User = hg

[topsecret.server.com]
Port = 50022
ForwardX11 = no

解析配置文件

>>> import configparser # 导入模块
>>> config = configparser.ConfigParser()  #实例化(生成对象)
>>> config.sections()  #调用sections方法
[]
>>> config.read('example.ini')  # 读配置文件(注意文件路径)
['example.ini']
>>> config.sections() #调用sections方法(默认不会读取default)
['bitbucket.org', 'topsecret.server.com']
>>> 'bitbucket.org' in config #判断元素是否在sections列表内
True
>>> 'bytebong.com' in config
False
>>> config['bitbucket.org']['User'] # 通过字典的形式取值
'hg'
>>> config['DEFAULT']['Compression']
'yes'
>>> topsecret = config['topsecret.server.com']
>>> topsecret['ForwardX11']
'no'
>>> topsecret['Port']
'50022'
>>> for key in config['bitbucket.org']: print(key) # for循环 bitbucket.org 字典的key
...
user
compressionlevel
serveraliveinterval
compression
forwardx11
>>> config['bitbucket.org']['ForwardX11']
'yes'

其它增删改查语法

[group1] # 支持的两种分隔符“=”, “:”
k1 = v1
k2:v2

[group2]
k1 = v1

import ConfigParser

config = ConfigParser.ConfigParser()
config.read('i.cfg')

# ########## 读 ##########
#secs = config.sections()
#print(secs)
#options = config.options('group2') # 获取指定section的keys
#print(options)

#item_list = config.items('group2') # 获取指定 section 的 keys & values ,key value 以元组的形式
#print(item_list)

#val = config.get('group1','key') # 获取指定的key 的value
#val = config.getint('group1','key')

# ########## 改写 ##########
#sec = config.remove_section('group1') # 删除section 并返回状态(true, false)
#config.write(open('i.cfg', "w")) # 对应的删除操作要写入文件才会生效

#sec = config.has_section('wupeiqi')
#sec = config.add_section('wupeiqi')
#config.write(open('i.cfg', "w")) # 


#config.set('group2','k1',11111)
#config.write(open('i.cfg', "w"))

#config.remove_option('group2','age')
#config.write(open('i.cfg', "w"))


hashlib模块

作用:用于加密相关的操作

主要提供 SHA1, SHA224, SHA256, SHA384, SHA512 ,MD5 算法

import hashlib

m = hashlib.md5()
m.update(b"Hello") 

print(m.digest())  # b"x8bx1ax99Sxc4ax12x96xa8'xabxf8xc4xx04xd7"

m.update(b"It's been a long time since last time we ...")

print(m.digest()) # 2进制格式hash

print(len(m.hexdigest())) #16进制格式hash



import hashlib

# ######## md5 ########

hash = hashlib.md5()
hash.update(b'admin')
print(hash.hexdigest())  # 21232f297a57a5a743894a0e4a801fc3

# ######## sha1 ########

hash = hashlib.sha1()
hash.update(b'admin')
print(hash.hexdigest())  # d033e22ae348aeb5660fc2140aec35850c4da997

# ######## sha256 ########

hash = hashlib.sha256()
hash.update(b'admin')
print(hash.hexdigest())  # 8c6976e5b5410415bde908bd4dee15dfb167a9c873fc4bb8a81f6f2ab448a918


# ######## sha384 ########

hash = hashlib.sha384()
hash.update(b'admin')
print(hash.hexdigest())  # 9ca694a90285c034432c9550421b7b9dbd5c0f4b6673f05f6dbce58052ba20e4248041956ee8c9a2ec9f10290cdc0782

# ######## sha512 ########

hash = hashlib.sha512()
hash.update(b'admin')
print(hash.hexdigest())  # c7ad44cbad762a5da0a452f9e854fdc1e0e7a52a38015f23f3eab1d80b931dd472634dfac71cd34ebc35d16ab7fb8a90c81f975113d6c7538dc69dd8de9077ec

HASH

Hash,一般翻译做“散列”,也有直接音译为”哈希”的,就是把任意长度的输入(又叫做预映射,pre-image),通过散列算法,变换成固定长度的输出,该输出就是散列值。这种转换是一种压缩映射,也就是,散列值的空间通常远小于输入的空间,不同的输入可能会散列成相同的输出,而不可能从散列值来唯一的确定输入值。

简单的说就是一种将任意长度的消息压缩到某一固定长度的消息摘要的函数。

HASH主要用于信息安全领域中加密算法,他把一些不同长度的信息转化成杂乱的128位的编码里,叫做HASH值.也可以说,hash就是找到一种数据内容和数据存放地址之间的映射关系

MD5

什么是MD5算法

MD5讯息摘要演算法(英语:MD5 Message-Digest Algorithm),一种被广泛使用的密码杂凑函数,可以产生出一个128位的散列值(hash value),用于确保信息传输完整一致。MD5的前身有MD2、MD3和MD4。

MD5功能

输入任意长度的信息,经过处理,输出为128位的信息(数字指纹);
不同的输入得到的不同的结果(唯一性);

MD5算法的特点

压缩性:任意长度的数据,算出的MD5值的长度都是固定的
容易计算:从原数据计算出MD5值很容易
抗修改性:对原数据进行任何改动,修改一个字节生成的MD5值区别也会很大
强抗碰撞:已知原数据和MD5,想找到一个具有相同MD5值的数据(即伪造数据)是非常困难的。

MD5算法是否可逆?

MD5不可逆的原因是其是一种散列函数,使用的是hash算法,在计算过程中原文的部分信息是丢失了的。

MD5用途:

防止被篡改:

比如发送一个电子文档,发送前,我先得到MD5的输出结果a。然后在对方收到电子文档后,对方也得到一个MD5的输出结果b。如果a与b一样就代表中途未被篡改。

比如我提供文件下载,为了防止不法分子在安装程序中添加木马,我可以在网站上公布由安装文件得到的MD5输出结果。
SVN在检测文件是否在CheckOut后被修改过,也是用到了MD5.

防止直接看到明文:

现在很多网站在数据库存储用户的密码的时候都是存储用户密码的MD5值。这样就算不法分子得到数据库的用户密码的MD5值,也无法知道用户的密码。(比如在UNIX系统中用户的密码就是以MD5(或其它类似的算法)经加密后存储在文件系统中。当用户登录的时候,系统把用户输入的密码计算成MD5值,然后再去和保存在文件系统中的MD5值进行比较,进而确定输入的密码是否正确。通过这样的步骤,系统在并不知道用户密码的明码的情况下就可以确定用户登录系统的合法性。这不但可以避免用户的密码被具有系统管理员权限的用户知道,而且还在一定程度上增加了密码被破解的难度。)

防止抵赖(数字签名):

这需要一个第三方认证机构。例如A写了一个文件,认证机构对此文件用MD5算法产生摘要信息并做好记录。若以后A说这文件不是他写的,权威机构只需对此文件重新产生摘要信息,然后跟记录在册的摘要信息进行比对,相同的话,就证明是A写的了。这就是所谓的“数字签名”。



subprocess模块

作用:提供统一的模块来实现对系统命令或脚本的调用

三种执行命令的方法

subprocess.run(*popenargs, input=None, timeout=None, check=False, **kwargs) #官方推荐

subprocess.call(*popenargs, timeout=None, **kwargs) #跟上面实现的内容差不多,另一种写法

subprocess.Popen() #上面各种方法的底层封装

run方法

标准写法

subprocess.run(['df','-h'],stderr=subprocess.PIPE,stdout=subprocess.PIPE,check=True)
涉及到管道|的命令需要这样写,建立管道

subprocess.run('df -h|grep disk1',shell=True) #shell=True的意思是这条命令直接交给系统去执行,不需要python负责解析,过滤disk1的文件

call方法

#执行命令,返回命令执行状态 , 0 or 非0
>>> retcode = subprocess.call(["ls", "-l"])

#执行命令,如果命令结果为0,就正常返回,否则抛异常
>>> subprocess.check_call(["ls", "-l"])
0

#接收字符串格式命令,返回元组形式,第1个元素是执行状态,第2个是命令结果 
>>> subprocess.getstatusoutput('ls /bin/ls')
(0, '/bin/ls')

#接收字符串格式命令,并返回结果
>>> subprocess.getoutput('ls /bin/ls')
'/bin/ls'

#执行命令,并返回结果,注意是返回结果,不是打印,下例结果返回给res
>>> res=subprocess.check_output(['ls','-l'])
>>> res
b'total 0
drwxr-xr-x 12 alex staff 408 Nov 2 11:05 OldBoyCRM
'

Popen方法

常用参数:

args:shell命令,可以是字符串或者序列类型(如:list,元组)
stdin, stdout, stderr:分别表示程序的标准输入、输出、错误句柄
preexec_fn:只在Unix平台下有效,用于指定一个可执行对象(callable object),它将在子进程运行之前被调用
shell:同上
cwd:用于设置子进程的当前目录
env:用于指定子进程的环境变量。如果env = None,子进程的环境变量将从父进程中继承。

a=subprocess.run('sleep 10',shell=True,stdout=subprocess.PIPE)
# 直接在主进程中执行,等待当前进程执行,再往后执行
a=subprocess.Popen('sleep 10',shell=True,stdout=subprocess.PIPE)
#发起一个子进程,与原有的主进程同时执行,执行完成将子进程的结果返回给主进程

a.poll()  # 获取子进程返回的结果

a.wait()  # 停止当前主进程,等待发起的子进程的结果

a.terminate()  # 终止所启动的进程

a.kill()  # 杀死所启动的进程

a.communicate()与启动的进程交互,发送数据到stdin,并从stdout接收输出,然后等待任务结束,只交互一次

>>> a = subprocess.Popen('python3 guess_age.py',stdout=subprocess.PIPE,stderr=subprocess.PIPE,stdin=subprocess.PIPE,shell=True)

>>> a.communicate(b'22')  # bytes类型

(b'your guess:try bigger
', b'')



a.send_signal(signal.xxx)发送系统信号

a.pid 拿到所启动进程的进程号


logging模块

作用:提供了标准的日志接口

logging的日志可以分为 debug(), info(), warning(), error() and critical()5个级别

1.简单的将日志打印到屏幕

import logging

logging.debug('This is debug message')
logging.info('This is info message')
logging.warning('This is warning message')


屏幕上打印:
WARNING:root:This is warning message

默认情况下,logging将日志打印到屏幕,日志级别为WARNING;
日志级别大小关系为:CRITICAL > ERROR > WARNING > INFO > DEBUG > NOTSET,当然也可以自己定义日志级别。

2.通过logging.basicConfig函数对日志的输出格式及方式做相关配置

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='myapp.log',
                filemode='w')
    
logging.debug('This is debug message')
logging.info('This is info message')
logging.warning('This is warning message')

 

./myapp.log文件中内容为:
Sun, 24 May 2009 21:48:54 demo2.py[line:11] DEBUG This is debug message
Sun, 24 May 2009 21:48:54 demo2.py[line:12] INFO This is info message
Sun, 24 May 2009 21:48:54 demo2.py[line:13] WARNING This is warning message

logging.basicConfig函数各参数:

filename: 指定日志文件名
filemode: 和file函数意义相同,指定日志文件的打开模式,'w’或’a’
format: 指定输出的格式和内容,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 用户输出的消息

datefmt: 指定时间格式,同time.strftime()
level: 设置日志级别,默认为logging.WARNING
stream: 指定将日志的输出流,可以指定输出到sys.stderr,sys.stdout或者文件,默认输出到sys.stderr,当stream和filename同时指定时,stream被忽略

3.将日志同时输出到文件和屏幕

Python 使用logging模块记录日志涉及四个主要类,使用官方文档中的概括最为合适:

logger提供了应用程序可以直接使用的接口;
handler将(logger创建的)日志记录发送到合适的目的输出;
filter提供了细度设备来决定输出哪条日志记录;
formatter决定日志记录的最终输出格式。

他们之间的关系是这样的
enter description here

logger

每个程序在输出信息之前都要获得一个Logger。Logger通常对应了程序的模块名,比如聊天工具的图形界面模块可以这样获得它的Logger:

LOG=logging.getLogger(”chat.gui”)

绑定handler和filters

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():可以设置的日志级别

handler

handler对象负责发送相关的信息到指定目的地。Python的日志系统有多种Handler可以使用。有些Handler可以把信息输出到控制台,有些Handler可以把信息输出到文件,还有些 Handler可以把信息发送到网络上。如果觉得不够用,还可以编写自己的Handler。可以通过addHandler()方法添加多个多handler

Handler.setLevel(lel):
指定被处理的信息级别,低于lel级别的信息将被忽略

Handler.setFormatter():
给这个handler选择一个格式
Handler.addFilter(filt)、Handler.removeFilter(filt):
新增或删除一个filter对象
每个Logger可以附加多个Handler。

接下来我们就来介绍一些常用的Handler:
logging.StreamHandler 使用这个Handler可以向类似与sys.stdout或者sys.stderr的任何文件对象(file object)输出信息。
logging.FileHandler 和StreamHandler 类似,用于向一个文件输出日志信息。不过FileHandler会帮你打开这个文件

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并不会被更名,而是被删除。
logging.handlers.TimedRotatingFileHandler

这个Handler和RotatingFileHandler类似,不过,它没有通过判断文件大小来决定何时重新创建日志文件,而是间隔一定时间就 自动创建新的日志文件。重命名的过程与RotatingFileHandler类似,不过新的文件不是附加数字,而是当前时间。它的函数是:

TimedRotatingFileHandler( filename [,when [,interval [,backupCount]]])
其中filename参数和backupCount参数和RotatingFileHandler具有相同的意义。

interval是时间间隔。

when参数是一个字符串。表示时间间隔的单位,不区分大小写。它有以下取值:

S 秒
M 分
H 小时
D 天
W 每星期(interval==0时代表星期一)
midnight 每天凌晨

formatter 组件

日志的formatter是个独立的组件,可以跟handler组合
fh = logging.FileHandler(“access.log”)
formatter = logging.Formatter(’%(asctime)s - %(name)s - %(levelname)s - %(message)s’)

fh.setFormatter(formatter) #把formmater绑定到fh上

filter 组件

如果你想对日志内容进行过滤,就可自定义一个filter

class IgnoreBackupLogFilter(logging.Filter):
""“忽略带db backup 的日志”""
def filter(self, record): #固定写法
return “db backup” not in record.getMessage()
注意filter函数会返加True or False,logger根据此值决定是否输出此日志

然后把这个filter添加到logger中
logger.addFilter(IgnoreBackupLogFilter())
下面的日志就会把符合filter条件的过滤掉

logger.debug(“test …”)
logger.info(“test info …”)
logger.warning(“start to run db backup job …”)
logger.error(“test error …”)

一个同时输出到屏幕、文件、带filter的完成例子

import logging



class IgnoreBackupLogFilter(logging.Filter):
    """忽略带db backup 的日志"""
    def filter(self, record): #固定写法
        return   "db backup" not in record.getMessage()

1.生成 logger 对象
logger =logging.getLogger("web")
logger.setLevel(logging.DEBUG)  # 设置日志级别



1.1 把filter对象添加到logger中 过滤日志
logger.addFilter(IgnoreBackupLogFilter())

2. 生成 handler对象
ch = logging.StreamHandler()
ch.setLevel(logging.INFO)

fh = logging.FileHandler("web.log")
fh = handlers.RotatingFileHandler( "web.log",maxBytes=10,backupCount=3)
fh = handlers.TimedRotatingFileHandler( "web.log",when="S",interval=5,backupCount=3)
fh.setLevel(logging.WARNING)

2.1 把 handler对象 绑定到logger
logger.addHandler(ch)
logger.addHandler(fh)

3.生成formatter 对象
3.1 把formatter 对象 绑定handler对象
file_formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
console_formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(lineno)d - %(message)s')

ch.setFormatter(console_formatter)
fh.setFormatter(file_formatter)



logger.warning("test log ")
logger.info("test log 2")
logger.debug("test log 3")
logger.debug("test log db backup 3")

#console : INFO
#global : DEBUG  default level : warning
#file :Warning

全局设置为DEBUG后, console handler 设置为INFO, 如果输出的日志级别是debug, 那就不会在屏幕上打印

re模块

作用:字符串的匹配规则

元字符

'**.**'  匹配除 
 换行符以外的任意字符。
'**^**'  匹配字符串以...开头。
'A'   匹配字符串以...开头。
'**$**'  匹配字符串以...结尾。
''  匹配字符串以...结尾。
a|b  匹配字符a或字符b
'[...]'	 匹配字符组中的字符,单个位置
‘[^...]’ 匹配除字符组当中的字符外的任意字符
‘(...)’  分组匹配,按照括号内的表达式匹配

'd'  匹配数字0-9
'D'  匹配非数字
'w' 	匹配字母或数字或下划线
'W'	匹配非字母或数字或下划线
's'	匹配任意的空白符 
 
 	
'S'	匹配非空白符

任意一对大小写的字符组:匹配所有字符
‘[dD]’  匹配任意的字符


	匹配一个换行符
		匹配一个制表符
	匹配一个单词的结尾

量词

*	   匹配零次或更多次
+	   匹配一次或更多次
?	   匹配零次或一次
{n}	   匹配n次
{n,}   匹配n次或更多次
{n,m}   匹配n到m次

例子

正则 待匹配字符 匹配结果 说明
海. 海燕海娇海东 海燕海娇海东 匹配所有"海."的字符
^海. 海燕海娇海东 海燕 只从开头匹配"海."
海.$ 海燕海娇海东 海东 只匹配结尾的"海.$"
李.? 李杰和李莲英和李二棍子 李杰李莲李二 ?表示重复零次或一次,即只匹配"李"后面一个任意字符
李.* 李杰和李莲英和李二棍子 李杰和李莲英和李二棍子 *表示重复零次或多次,即匹配"李"后面0或多个任意字符
李.+ 李杰和李莲英和李二棍子 李杰和李莲英和李二棍子 +表示重复一次或多次,即只匹配"李"后面1个或多个任意字符
李.{1,2} 李杰和李莲英和李二棍子 李杰和李莲英李二棍 {1,2}匹配1到2次任意字符

注意:前面的*,+,?等都是贪婪匹配,也就是尽可能匹配,后面加?号使其变成惰性匹配

转义符‘’

在正则表达式中,有很多有特殊意义的是元字符,比如d和s等,如果要在正则中匹配正常的"d"而不是"数字"就需要对""进行转义,变成’’。

在python中,无论是正则表达式,还是待匹配的内容,都是以字符串的形式出现的,在字符串中也有特殊的含义,本身还需要转义。所以如果匹配一次"d",字符串中要写成’d’,那么正则里就要写成"\d",这样就太麻烦了。这个时候我们就用到了r’d’这个概念,此时的正则是r’d’就可以了。

分组匹配:

(?p…)给分组匹配取个名字,匹配到的值可以通过name取出来,以key-value的形式,name为key,匹配的值为value.

正则 待匹配字符 匹配结果 说明
d d False 因为在正则表达式中是有特殊意义的字符,所以要匹配d本身,用表达式d无法匹配
d d True 转义之后变成,即可匹配
“\d” ‘d’ True 如果在python中,字符串中的’‘也需要转义,所以每一个字符串’'又需要转义一次
r’d’ r’d’ True 在字符串之前加r,让整个字符串不转义

贪婪匹配

贪婪匹配:在满足匹配时,匹配尽可能长的字符串,默认情况下,采用贪婪匹配

几个常用的非贪婪匹配Pattern

*? 重复任意次,但尽可能少重复
+? 重复1次或更多次,但尽可能少重复
?? 重复0次或1次,但尽可能少重复
{n,m}? 重复n到m次,但尽可能少重复
{n,}? 重复n次以上,但尽可能少重复

.*? 用法

. 是任意字符
* 是取 0 至 无限长度
? 是非贪婪模式。
合在一起就是 取尽量少的任意字符,一般不会这么单独写,他大多用在:
.*?x
就是取前面任意长度的字符,直到一个x出现

re模块下的常用方法

import re

ret = re.findall('a', 'eva egon yuan')  # 返回所有满足匹配条件的结果,放在列表里
print(ret) #结果 : ['a', 'a']

ret = re.search('a', 'eva egon yuan').group()
print(ret) #结果 : 'a'
# 函数会在字符串内查找模式匹配,只到找到第一个匹配然后返回一个包含匹配信息的对象,该对象可以
# 通过调用group()方法得到匹配的字符串;如果字符串没有匹配,则返回None,调用group()方法报错

ret = re.match('a', 'abc').group()  # 同search,不过只从字符串开头处进行匹配
print(ret)
#结果 : 'a'

注意:
当匹配的规则中有分组时,可以通过调用groups(),拆开的得到多个分组匹配的值。

ret = re.split('[ab]', 'abcd')  # 先按'a'分割得到''和'bcd',在对''和'bcd'分别按'b'分割
print(ret)  # ['', '', 'cd']

ret = re.sub('d', 'H', 'eva3egon4yuan4', 1)#将数字替换成'H',参数1表示只替换1个
print(ret) #evaHegon4yuan4

ret = re.subn('d', 'H', 'eva3egon4yuan4')#将数字替换成'H',返回元组(替换的结果,替换了多少次)
print(ret)

obj = re.compile('d{3}')  #将正则表达式编译成为一个 正则表达式对象,规则要匹配的是3个数字
ret = obj.search('abc123eeee') #正则表达式对象调用search,参数为待匹配的字符串
print(ret.group())  #结果 : 123

import re
ret = re.finditer('d', 'ds3sy4784a')   #finditer返回一个存放匹配结果的迭代器
print(ret)  # <callable_iterator object at 0x10195f940>
print(next(ret).group())  # 查看第一个结果
print(next(ret).group())  # 查看第二个结果
print([i.group() for i in ret])  # 查看剩余的左右结果

优先级问题

1 findall的优先级查询:

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']

2 split的优先级查询

ret=re.split("d+","eva3egon4yuan")
print(ret) #结果 : ['eva', 'egon', 'yuan']

ret=re.split("(d+)","eva3egon4yuan")
print(ret) #结果 : ['eva', '3', 'egon', '4', 'yuan']

#在匹配部分加上()之后所切出的结果是不同的,
#没有()的没有保留所匹配的项,但是有()的却能够保留了匹配的项,
#这个在某些需要保留匹配部分的使用过程是非常重要的。

Flags标志位

re.I 不区分大小写
re.M 多行模式,改变^和$的行为
re.S 点可以匹配任意的字符,包括换行符

原文地址:https://www.cnblogs.com/james201133002/p/9274803.html