Python模块

 一、模块

模块就是写好的功能放在一个文件里,即py文件

 

模块的种类:

① 内置模块:安装python解释器的时候就装上了

② 第三方模块、扩展模块:不在内置模块不一定不重要,根据用户需求安装使用

③ 自定义模块:自己写的py文件

 

二、序列化模块

序列:列表、元组、字符串、bytes

序列化:把一个数据类型转换成字符串、bytes类型的过程就是序列化

 

数据类型序列化的场景:

① 把一个数据类型存储在文件中

② 把一个数据类型通过网络传输的时候

 

eval和exec:用户输入,文件读入,网络传入都不能使用,存在风险,极其不安全。

 

import json    # 导入json模块

在json格式下,所欲的字符串都是双引号。

 

json.dumps(obj)   序列化的过程,转换为字符串

import json                                     # 导入json模块
dic = {'province':'广东省','city':'深圳市'}
s = json.dumps(dic)                             # 序列化的过程
print(s,type(s))

# {"province": "u5e7fu4e1cu7701", "city": "u6df1u5733u5e02"} <class 'str'>

 

json.loads(str)    反序列化的过程,转换为原本的类型

import json                                         # 导入json模块
dic = {'province':'广东省','city':'深圳市'}
s = json.dumps(dic)                                 # 序列化的过程
dic2 = json.loads(s)                                # 反序列化的过程
print(dic2,type(dic2))

# {'province': '广东省', 'city': '深圳市'} <class 'dict'>

 

json.dump(obj,f)     序列化的过程,将字典写入到文件中

import json
dic = {'a':1,'lis':[1,2,3],'city':'gz'}
f = open('aaa','a',encoding='utf-8')
json.dump(dic,f)                        # 把字典写入到文件中
f.close()

'''
{"a": 1, "lis": [1, 2, 3], "city": "gz"}
'''

 

 json.load(f)

import json
f = open('aaa',encoding='utf-8')
dic = json.load(f)              # 将文件的内容读取出来,并且还原原来的类型
print(dic)                      # {'a': 1, 'lis': [1, 2, 3], 'city': 'gz'}

 

json的优点:

① 所有的语言都通用

json的缺点:

① 只支持非常少的数据类型

② 对数据类型的约束很苛刻

③ 字典的key必须是字符串

④ 只支持数据类型:数字、字符串、列表、字典 

 

使用json的场景:

  序列化的内容是简单的内容,比如字典,字符串类型的就选择json,因为json有优势,可以直接看到结果,或者从文件里 能看到结果。

  前端使用的是json,网络传输的数据大部分也是使用json

 

json的特点:

① 可以在所有的语言中通用

② 能够处理的数据类型非常优先(网络操作中,以及多语言环境中,传递字典、数字、字符串、列表等简单的数据类型时使用)

③ json的字典有非常苛刻的要求:字典的key必须是字符串,且所有的字符串都必须是用" " 表示

④ dumps(dict/list) 把dict/list 转化成str,这是序列化

⑤ loads(str) 把str转化为dict/list,这是反序列化

⑥ dump(dict/list,f) 把dict/list写入文件,这是序列化

⑦ load(f) 文件转化为原来的数据类型,这是反序列化

⑧ 多次dump进入文件中的数据load会报错

 

json的参数:

ensure_ascii:默认值True,如果dict内含有non-ASCII的字符,则会类似uXXXX的显示数据,设置成False后,就能正常显示

indent:应该是一个非负的整型,如果是0,或者为空,则一行显示数据,否则会换行且按照indent的数量显示前面的空白,这样打印出来的json数据也叫pretty-printed json

separators:分隔符,实际上是(item_separator, dict_separator)的一个元组,默认的就是(',',':');这表示dictionary内keys之间用“,”隔开,而KEY和value之间用“:”隔开。

encoding:默认是UTF-8,设置json数据的编码方式。

sort_keys:将数据根据keys的值进行排序。

 

pickle

import pickle

pickle和json的用法相似。

 

局限性:只有python语言支持

优点:支持几乎所有的数据类型

 

pickle操作文件必须是以+b的形式

pickle支持多次dump和多次load,需要使用try...except

 

① pickle多次dump

import pickle
lis = [1,2,3,{'a':1,'b':2,'c':['a','b','c'],'d':'gz'},'z','x']
f = open('aaa','ab')
for i in range(10):
    pickle.dump(lis,f)          # 循环多次写入文件
f.close()

 

② pickle多次load

import pickle
f = open('aaa','rb')
while 1:
    try:
        lis = pickle.load(f)
        print(lis)
    except EOFError:
        break
f.close()

'''
[1, 2, 3, {'a': 1, 'b': 2, 'c': ['a', 'b', 'c'], 'd': 'gz'}, 'z', 'x']
[1, 2, 3, {'a': 1, 'b': 2, 'c': ['a', 'b', 'c'], 'd': 'gz'}, 'z', 'x']
[1, 2, 3, {'a': 1, 'b': 2, 'c': ['a', 'b', 'c'], 'd': 'gz'}, 'z', 'x']
[1, 2, 3, {'a': 1, 'b': 2, 'c': ['a', 'b', 'c'], 'd': 'gz'}, 'z', 'x']
[1, 2, 3, {'a': 1, 'b': 2, 'c': ['a', 'b', 'c'], 'd': 'gz'}, 'z', 'x']
[1, 2, 3, {'a': 1, 'b': 2, 'c': ['a', 'b', 'c'], 'd': 'gz'}, 'z', 'x']
[1, 2, 3, {'a': 1, 'b': 2, 'c': ['a', 'b', 'c'], 'd': 'gz'}, 'z', 'x']
[1, 2, 3, {'a': 1, 'b': 2, 'c': ['a', 'b', 'c'], 'd': 'gz'}, 'z', 'x']
[1, 2, 3, {'a': 1, 'b': 2, 'c': ['a', 'b', 'c'], 'd': 'gz'}, 'z', 'x']
[1, 2, 3, {'a': 1, 'b': 2, 'c': ['a', 'b', 'c'], 'd': 'gz'}, 'z', 'x']
'''

 

三、时间模块

imprt time

 

三种格式:

① 时间戳时间:浮点数支撑,以秒为单位(方便计算机计算)

语法:time.time()

1970-1-1 0:0:0 格林威治时间,时间的起始点

import time
t = time.time()
print(t)            # 1536047063.2101386

 

② 格式化时间:字符串数据类型(显示给用户看)

time。strftime(字符串格式实际)

import time
fm1 = time.strftime('%Y-%m-%d')     # 年月日 2018-09-04
fm2 = time.strftime('%H:%M:%S')     # 时分秒 15:48:25
fm3 = time.strftime('%c')           # 外国格式 ue Sep  4 15:48:25 2018
fm4 = time.strftime('%X')           # 时分秒 15:48:25
fm5 = time.strftime('%x')           # 月/日/年 09/04/18

 

③ 结构化时间: 元组格式,用于时间戳时间和格式化时间之间的转化

time.localtime()

import time
t = time.localtime()
print(t)

'''
time.struct_time(tm_year=2018, tm_mon=9, tm_mday=4, tm_hour=15, tm_min=52, tm_sec=5, tm_wday=1, tm_yday=247, tm_isdst=0)
'''

 

时间格式的转化:

 

格式化时间 ---> 时间戳时间

fmt = time.strftime('%x %X')       # 格式化时间
stt = time.strptime(fmt,'%x %X')   # 结构化时间
t = time.mktime(stt)               # 时间戳时间
print(fmt)
print(stt)
print(t)

'''
09/04/18 15:56:53
time.struct_time(tm_year=2018, tm_mon=9, tm_mday=4, tm_hour=15, tm_min=56, tm_sec=53, tm_wday=1, tm_yday=247, tm_isdst=-1)
1536047813.0
'''

 

时间戳时间 ---> 格式化时间

t = time.time()                             # 时间戳时间
stt = time.localtime(t)                     # 结构化时间
fmt = time.strftime('%Y-%m-%d %X',stt)      # 格式化时间
print(t)
print(stt)
print(fmt)

'''
1536048042.169353
time.struct_time(tm_year=2018, tm_mon=9, tm_mday=4, tm_hour=16, tm_min=0, tm_sec=42, tm_wday=1, tm_yday=247, tm_isdst=0)
2018-09-04 16:00:42
'''

 

 

结构化时间 --> %a %b %d %H:%M:%S %Y串

t = time.asctime()                              # 结构化时间 %a %b %d %H:%M:%S %Y串
t1 = time.asctime(time.localtime(2000000000))   # 结构化时间 %a %b %d %H:%M:%S %Y串
print(t)                    # Tue Sep  4 16:04:17 2018
print(t1)                   # Wed May 18 11:33:20 2033

 

时间戳 --> %a %b %d %H:%M:%S %Y串

t = time.ctime()
t2 = time.ctime(2000000000)
print(t)                        # Tue Sep  4 16:06:32 2018
print(t2)                       # Wed May 18 11:33:20 2033

 

四、随机数模块

随机小数(一般用于科学计算)

random.random()    0-1之间的小数(0,1)

import random
r = random.random()               # 0-1之间的小数
print(r)
print(round(r,2))                 # 保留两位小数

'''
0.13465619587224942
0.13
'''

 

random.uniform(a,b)  a-b之间的小数 (a,b)

r1 = random.uniform(10,100)         # 10-100之间的小数
r2 = random.uniform(100,10)         # 10-100之间的小数
print(r1)
print(r2)

'''
66.24475927171648
31.986449179748902
'''

 

随机整数

random.randint(a,b)  a-b之间的整数 [a,b]

r1 = random.randint(5,10)           # 5-10之间的整数 [5-10]
print(r1)                           # 5

 

random.randrange(a,b)      a-b之间的整数[a,b)

r1 = random.randrange(1,100)          # 1-100之间的整数 [1,100)
print(r1)                             # 88

 

random.randrange(a,b,c)   a-b步长为c的整数 [a,b)

r1 = random.randrange(0,100,2)          # 0-100之间的偶数的随机数,[0,100)
print(r1)                               # 52

 

列表中的随机元素

random.choice(list/tuple/range/str)       从列表总随机抽取一个元素

lis = ['a','b','c',1,2,3]
r1 = random.choice(lis)             # 从列表中随机一个元素
print(r1)                           # 3

 

random.sample(list,n)    从列表中随机抽取n个元素,组成列表

lis = ['a','b','c',1,2,3]
r = random.sample(lis,2)            # 从列表中随机2个元素组成列表
print(r)                            # ['a', 'c']

 

列表的乱序排列(在原列表的上修改)

random.shuffle(list)     在原列表的基础上打乱列表元素,节省内存

lis = ['a','b','c',1,2,3]
random.shuffle(lis)                 # 打乱列表的元素
print(lis)                          # [3, 2, 1, 'b', 'c', 'a']

 

验证码

import random
def verification_code(n=6,letter_flag = True):
    code = ''
    for i in range(n):
        c = str(random.randint(0,9))      # 0-9整数的随机数
        if letter_flag:                   # letter_flag随机字母
            cap = chr(random.randint(65,90))    # A-Z的随机字母,通过chr转化为字母
            low = chr(random.randint(97,122))   # a-z的随机字母,通过chr转化为字母
            c = random.choice([c,cap,low])
        code += c
    return code

 

五、OS模块

__file__  当前文件位置

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.system("bash command") 运行shell命令,直接显示
os.popen("bash command).read() 运行shell命令,获取执行结果
os.getcwd() 获取当前工作目录,即当前python脚本工作的目录路径
os.chdir("dirname") 改变当前脚本工作目录;相当于shell下cd


os.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.getatime(path) 返回path所指向的文件或者目录的最后访问时间
os.path.getmtime(path) 返回path所指向的文件或者目录的最后修改时间
os.path.getsize(path) 返回path的大小
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)是创建时间(详细信息参见平台的文档)。
os模块的属性

os.sep    输出操作系统特定的路径分隔符,win下为"\",Linux下为"/"
os.linesep    输出当前平台使用的行终止符,win下为"
",Linux下为"
"
os.pathsep    输出用于分割文件路径的字符串 win下为;,Linux下为:
os.name    输出字符串指示当前使用平台。win->'nt'; Linux->'posix'

 

六、sys模块

sys.path   一个模块能否被导入,就看这个模块所在的目录在不在sys.path路径中,import某个模块会从头到尾取找某个模块,找到就返回

内置模块在python/lib,第三方模块在/venv/lib/site-pakcages

内置模块和第三方扩展模块都不需要处理,sys.path就可以直接调用

自定义模块的导入工作需要手动修改sys.path,当前文件夹的首个位置

sys.argv 执行py文件的时候传入的参数
sys.path 查看模块搜索路径 import 模块的时候从这个路径下来寻找
sys.modules 查看当前导入的模块和它的命名空间

sys.argv 命令行参数List,第一个元素是程序本身路径
sys.exit(n) 退出程序,正常退出时exit(0)
sys.version 获取Python解释程序的版本信息
sys.maxint 最大的Int值
sys.path 返回模块的搜索路径,初始化时使用PYTHONPATH环境变量的值
sys.platform 返回操作系统平台名称

七、collection 模块

collection 根据基础数据类型做了一些扩展:

① Counter

② 有序字典

③ 默认字典

④ 可命名元组

⑤ 双端队列

 

Counter

Counter类的目的是用来跟踪值出现的次数。它是一个无序的容器类型,以字典的键值对形式存储,其中元素作为key,其计数作为value。

from collections import Counter
c = Counter('abcabcde')         # 可传入可迭代对象来创建(list、tuple、dict、str等)
print(c)                        # Counter({'a': 2, 'b': 2, 'c': 2, 'd': 1, 'e': 1})

print(c['z'])                   # 访问的键不存在,返回0

 

计数器的更新(增加和减少)

from collections import Counter
c = Counter('hello')
c.update('hello')                  # 计算器的更新:增加
print(c)                           # Counter({'l': 4, 'h': 2, 'e': 2, 'o': 2})
c.subtract('hello')                # 计算器的更新:减少
print(c)                           # Counter({'l': 2, 'h': 1, 'e': 1, 'o': 1})

 

常用操作:

elements()      # 返回一个迭代器。元素被重复了多少次,在该迭代器中就包含多少个该元素。元素排列无确定顺序,个数小于1的元素不被包含。
sum(c.values())  # 所有计数的总数
c.clear()  # 重置Counter对象,注意不是删除
list(c)  # 将c中的键转为列表
set(c)  # 将c中的键转为set
dict(c)  # 将c中的键值对转为字典
c.items()  # 转为(elem, cnt)格式的列表
Counter(dict(list_of_pairs))  # 从(elem, cnt)格式的列表转换为Counter类对象
c.most_common()[:-n:-1]  # 取出计数最少的n-1个元素
c += Counter()  # 移除0和负值
del c['a']      # 删除键值对

 

 

OrderedDict 有序字典,python3.6版本以后的字典是有序的

from collections import OrderedDict
dic = OrderedDict([('a',1),('b',2)])     # OrderedDict 的创建
print(dic)                  # OrderedDict([('a', 1), ('b', 2)])

defaultdict  默认字典

defaultdict类的初始化函数接受一个类型作为参数,当所访问的键不存在的时候,可以实例化一个值作为默认值

from collections import defaultdict
func = lambda :'default'
l = defaultdict(func)
print(l['a'])       # 不存在该键,会返回默认值
l['a'] = 1
print(l)

'''
default
defaultdict(<function <lambda> at 0x0000027577BE2E18>, {'a': 1})

namedtuple  可命名元组

语法:namedtuple(类名,[对象属性])

使用场景:元组的元素都有固定的意义,就用可命名元组,非常类似一个只有属性没有属性的类。

只有属性没有方法,当定义一个类,属性是不变的,没有方法,就可以使用可命名元组

特点:

a.元组的是不可变的,元素不能修改

b.元组要描述很多值,用户能直观地看到

c.和元组没有交集,不能通过索引访问,只能通过属性访问

d.一旦实例化就不能修改属性的值

from collections import namedtuple
today = namedtuple('Date_today',['year','month','day'])
d = today(2018,9,5)
print(d.year)           # 2018
print(d.month)          # 9
print(d.day)            # 5
print(type(d))          # <class '__main__.Date_today'>

数据类型:队列

队列是一种数据类型,python里存在于模块,导入queue模块才能使用

队列的特性是先进先出,类似与买车票,队列能管理程序

所有的数据类型都能使用方法put()

import queue
q = queue.Queue()

queue.queue类即是一个队列的同步实现。队列长度可为无限或者有限。可通过queue的构造函数的可选参数maxsize来设定队列长度。如果maxsize小于1就表示队列长度无限。

|queue.Queue|先进先出队列|
|queue.LifoQueue|后进先出队列|
|queue.PriorityQueue|优先级队列|
|queue.deque|双线队列|

get()    # 将值放入队列中

put()    # 将值从队列中取出

import queue
q = queue.Queue()
q.get(1)            # 将一个值放入队列中
print(q.put(1))     # 将一个值从队列中取出

其他方法:

q.qsize() 返回队列的大小
q.empty() 如果队列为空,返回True,反之False
q.full() 如果队列满了,返回True,反之False
q.full 与 maxsize 大小对应
q.get([block[, timeout]]) 获取队列,timeout等待时间
q.get_nowait() 相当q.get(False)
非阻塞 q.put(item) 写入队列,timeout等待时间
q.put_nowait(item) 相当q.put(item, False)
q.task_done() 在完成一项工作之后,q.task_done() 函数向任务已经完成的队列发送一个信号
q.join() 实际上意味着等到队列为空,再执行别的操作

deque 双端队列(效率比列表快)

列表insert插入操作是将所有的元素往后移,效率比较慢,所以列表不能使用insert的方法

双端队列的数据结构是链表

双端列表的操作方法跟列表相似

增加方法:

from collections import deque
d = deque()
d.append(1)
d.append(2)
d.appendleft(3)
print(d)            # deque([3, 1, 2])

其他的方法:

clear(清空队列)

copy(浅拷贝)

count(返回指定元素的出现次数)

extend(从队列右边扩展一个列表的元素)

extendleft(从队列左边扩展一个列表的元素)

index(查找某个元素的索引位置)

insert(在指定位置插入元素)---> 效率比列表高1000倍

pop(获取最右边一个元素,并在队列中删除)

popleft(获取最左边一个元素,并在队列中删除)

remove(删除指定元素)

reverse(队列反转)

rotate(把右边元素放到左边)

八、hashllib 模块

这是一个内部有不止一种算法的模块。

由于数据的不安全性,为了保证用户的信息的绝对安全,所以的密码都不能以明文的形式存储,而是使用密文的形式存储,这时可使用这个模块。

模块里的算法都是摘要算法,该算法有特下特点:

① 算法不可逆,即密文不能反推明文

② 不同的字符串通过这个算法计算的密文总是不同的

③ 相同的算法,相同的字符串,获得的结果总是相同

④ 不同的语言,不同的环境都能通用

该模块应用场景:

① 登陆验证

② 文件的一致性校验

模块里最常用的算法:

① MD5算法

② sha算法

MD5 算法

步骤:

① 必须初始化对象

② update() 将字符串转化为密文,该方法接收的只能是bytes类型

③ 通过hexdigest() 方法获得结果

import hashlib
md5_obj = hashlib.md5()         # 初始化对象
md5_obj.update('abcde'.encode('utf-8'))     # 只能接收bytes类型,转化为密文
ret = md5_obj.hexdigest()                 # 获取转化后的密文
print(ret)                      # b56b4d92b40713acc5af89985d4b786

登陆验证

import hashlib
def login(user,pwd):
    md5 = hashlib.md5() 
    md5.update(pwd)         # 将传入的密码转化为密文
    pwd = md5.hexdigest()
    with open('userinfo',encoding='utf-8') as f:
        for line in f:
            username,password = line.strip().split(',') 
            if user == username and pwd == password:
                return True
        else:
            return False

MD5算法的总结:

① 目前应用最广的字啊要算法,效率高,相对于SHA算法不复杂,如果只是传统的摘要不安全。

② 只要字符串不变,无论update多少次,结果都是一样的

③ 对象只能计算一次值,想再用MD5算法的方法,就需要重新实例化对象

④ 加密后的结果是一个32位16进制的字符串

import hashlib
md5_obj1 = hashlib.md5()
md5_obj1.update('mypassword'.encode('utf-8'))
ret1 = md5_obj1.hexdigest()

md5_obj2 = hashlib.md5()
md5_obj2.update('my'.encode('utf-8'))
md5_obj2.update('password'.encode('utf-8'))
ret2 = md5_obj2.hexdigest()

print(ret1 == ret2)         # True

SHA1 算法

使用方式和MD5一致,加密后的结果是一个40位16进制的字符串。

SHA 还有其他算法,SHA 后面的数字越大算法越复杂,但是耗时越久,结果越长,同时安全性越高。

步骤:

① 必须初始化对象

② update() 将字符串转化为密文,该方法接收的只能是bytes类型

③ 通过hexdigest() 方法获得结果

import hashlib
sha_obj = hashlib.sha1()
sha_obj.update('abced'.encode('utf-8'))  # 只接收bytes类型,转化为密文
ret = sha_obj.hexdigest()                # 40位十六进制的字符串
print(ret)                  # bc748caecb1333dca5cecfdbc5b19833f5e1374a

传统的摘要算法存在的问题:撞库(通过密文表对照推测结果)

解决撞库的方案:加盐(加强安全性)

import hashlib
# 加盐
md5_obj1 = hashlib.md5('hello'.encode('utf-8'))     # 加盐
md5_obj1.update('mypassword'.encode('utf-8'))
ret1 = md5_obj1.hexdigest()

# 传统摘要
md5_obj2 = hashlib.md5()
md5_obj2.update('mypassword'.encode('utf-8'))
ret2 = md5_obj2.hexdigest()

print(ret1,ret2)
# ret1 = 9402bc9c2e3e5cacced33cd10bc8f769
# ret2 = 34819d7beeabb9260a5c854bc85b3e44

但仍然不是绝对的安全,可能被恶意注册来获得密文表来对照推测结果和加盐方式,因此我们使用动态加盐

动态加盐即通过用户名在作为盐,一般情况用户名是唯一的,就算密码相同,密文也不一样。

# 动态加盐
import hashlib
def login(user,pwd):
    md5 = hashlib.md5(user.encode('utf-8'))     # 动态加盐
    md5.update(pwd)
    pwd = md5.hexdigest()

    with open('userinfo',encoding='utf-8') as f:
        for line in f:
            username,password = line.strip().split(',')
            if user == username and pwd == password:
                return True
        else:
            return False

文件的一致性校验

给一个文件总的所有内容进行摘要算法,得到一个MD5值

大文件应该改以rb的形式来读,读出来的是bytes,不用编码。但是不能按行读,也不能一次性读出来,可以使用read(n)的方式来读取

import os,hashlib
def get_md5(path,buffer = 1024):
    if os.path.exists(path):        # 判断文件是否存在
        path = os.path.abspath(path)    # 转化为绝对路径
        if os.path.isfile(path):        # 判断是否文件
            md5 = hashlib.md5()         # 初始化md5对象
            size = os.path.getsize(path)    # 获得文件的大小
            with open(path,'rb') as f:
                while size:
                    r = f.read(buffer)    # 一次读n个字节
                    size -= len(r)
                    md5.update(r)           # 转化为密文
            return md5.hexdigest()          # 返回MD5值

九、configparser 模块

configparser模块是用来解析ini配置文件的解析器

ini文件结构需要注意一下几点:

键值对可用=或者:进行分隔
section的名字是区分大小写的,而key的名字是不区分大小写的
键值对中头部和尾部的空白符会被去掉
值可以为多行
配置文件可以包含注释,注释以#或者;为前缀
注意:configparser有default_section的概念,默认为[DEFAULT]节,也就是之后的所有的section都有该默认section中的键值对

ConfigParser模块以ConfigParser类为例,其操作基本分为三类:1)初始化;2)读取配置;3)写入配置。

1. ConfigParser 初始化

使用ConfigParser 首选需要初始化实例,并读取配置文件:

cf = ConfigParser.ConfigParser() cf.read("配置文件名")

2. 基本的读取配置文件

-read(filename) 直接读取ini文件内容

-sections() 得到所有的section,并以列表的形式返回

-options(section) 得到该section的所有option

-items(section) 得到该section的所有键值对

-get(section,option) 得到section中option的值,返回为string类型

-getint(section,option) 得到section中option的值,返回为int类型,还有相应的getboolean()和getfloat() 函数。

 

3.基本的写入配置文件

-add_section(section) 添加一个新的section

-set( section, option, value) 对section中的option进行设置,需要调用write将内容写入配置文件。

十、logging 模块

 日志的分级记录:

  debug:   计算或工作的细节

  info:       记录用户的增删改查操作

  warning    警告操作

  error       错误操作

  critical     批判的错误,直接导致程序出错或退出

简单配置:

不能写中文,但不用创建对象

import logging
logging.basicConfig(level=logging.DEBUG,
                    format='%(asctime)s %(filename)s %(levelname)s %(message)s',
                    datefmt='%Y-%m-%d %H:%M:%S')

logging.debug('debug message')
logging.info('info message')
logging.warning('warning message')
logging.error('error message')
logging.critical('critical message')

'''
2018-09-06 17:24:11 exercise.py DEBUG debug message
2018-09-06 17:24:11 exercise.py INFO info message
2018-09-06 17:24:11 exercise.py WARNING warning message
2018-09-06 17:24:11 exercise.py ERROR error message
2018-09-06 17:24:11 exercise.py CRITICAL critical message
'''

了解一下 basicConfig 的参数都有哪些:

  • filename:即日志输出的文件名,如果指定了这个信息之后,实际上会启用 FileHandler,而不再是 StreamHandler,这样日志信息便会输出到文件中了。
  • filemode:这个是指定日志文件的写入方式,有两种形式,一种是 w,一种是 a,分别代表清除后写入和追加写入。
  • format:指定日志信息的输出格式,即上文示例所示的参数:
    • %(levelno)s:打印日志级别的数值。
    • %(levelname)s:打印日志级别的名称。
    • %(pathname)s:打印当前执行程序的路径,其实就是sys.argv[0]。
    • %(filename)s:打印当前执行程序名。
    • %(funcName)s:打印日志的当前函数。
    • %(lineno)d:打印日志的当前行号。
    • %(asctime)s:打印日志的时间。
    • %(thread)d:打印线程ID。
    • %(threadName)s:打印线程名称。
    • %(process)d:打印进程ID。
    • %(processName)s:打印线程名称。
    • %(module)s:打印模块名称。
    • %(message)s:打印日志信息。
  • datefmt:指定时间的输出格式。
  • style:如果 format 参数指定了,这个参数就可以指定格式化时的占位符风格,如 %、{、$ 等。
  • level:指定日志输出的类别,程序会输出大于等于此级别的信息。
  • stream:在没有指定 filename 的时候会默认使用 StreamHandler,这时 stream 可以指定初始化的文件流。
  • handlers:可以指定日志处理时所使用的 Handlers,必须是可迭代的。

对象的配置

① 可以写入多个文件,正常情况下只写一个

② 解决中文的问题

③ 同时向文件和屏幕输出内容

创建步骤:

① 先创建对象log对象,logger

② 创建一个控制文件输出的文件句柄

③ 创建控制屏幕输出的屏幕操作符

④ 创建一个格式

⑤ 文件句柄绑定一个格式

⑥ 屏幕操作符绑定一个格式

⑦ logger对象绑定文件句柄和屏幕操作符

import logging
logger = logging.getLogger()        # 创建logging的对象
logger.setLevel(logging.DEBUG)      # 设置告警等级DEBUG及以上告警
fh = logging.FileHandler('procedure.log',encoding='utf-8')   # 创建文件输出的文件操作符
sh = logging.StreamHandler()        # 创建控制屏幕输出的屏幕操作符
fmt = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s',
                        datefmt='%Y-%m-%d %H:%M:%S')    # 创建格式

fh.setFormatter(fmt)                # 文件操作符绑定格式
sh.setFormatter(fmt)                # 屏幕操作符绑定格式
sh.setLevel(logging.ERROR)        # 设置屏幕输出的告警等级
logger.addHandler(sh)               # 对象绑定屏幕控制符
logger.addHandler(fh)               # 对象绑定文件操作符

logging.debug('debug message')
logging.info('info message')
logging.warning('warning message')
logging.error('error message')
logging.critical('critical message')

'''
2018-09-06 17:34:49 - root - ERROR - error message
2018-09-06 17:34:49 - root - CRITICAL - critical message
'''

参考文档:https://cuiqingcai.com/6080.html

       https://www.cnblogs.com/yyds/p/6901864.html

原文地址:https://www.cnblogs.com/st-st/p/9581447.html