标签:hashlib osi 不同的 平台 内存地址 批注 amd 并且 不可
序列化的本质就是将一种数据结构(如字典、列表)等转换成一个特殊的序列(字符串或者bytes)的过程就叫做序列化。
如果你写入文件中的字符串是一个序列化后的特殊的字符串,那么当你从文件中读取出来,是可以转化回原数据结构的。
序列化模块就是将一个常见的数据结构转化成一个特殊的序列,并且这个特殊的序列还可以反解回去。它的主要用途:文件读写数据,网络传输数据。
json模块是将满足条件的数据结构转化成特殊的字符串,并且也可以反序列化还原回去。
上面介绍我已经说过了,序列化模块总共只有两种用法,要不就是用于网络传输的中间环节,要不就是文件存储的中间环节,所以json模块总共就有两对四个方法:
用于网络传输:dumps、loads
用于文件写读:dump、load
dumps、loads
import json
dic = {'k1':'v1','k2':'v2','k3':'v3'}
str_dic = json.dumps(dic) #序列化:将一个字典转换成一个字符串
print(type(str_dic),repr(str_dic))
结果:
#<class 'str'> '{"k3": "v3", "k1": "v1", "k2": "v2"}'
#注意,json转换完的字符串类型的字典中的字符串是由""表示的
import json
dic2 = json.loads(str_dic) #反序列化:将一个字符串格式的字典转换成一个字典
#注意,要用json的loads功能处理的字符串类型的字典中的字符串必须由""表示
print(type(dic2),dic2)
结果:
#<class 'dict'> {'k1': 'v1', 'k2': 'v2', 'k3': 'v3'}
list_dic = [1,['a','b','c'],3,{'k1':'v1','k2':'v2'}]
str_dic = json.dumps(list_dic) #也可以处理嵌套的数据类型
print(type(str_dic),repr(str_dic))
结果:
<class 'str'> '[1, ["a", "b", "c"], 3, {"k1": "v1", "k2": "v2"}]'
list_dic2 = json.loads(str_dic)
print(type(list_dic2),list_dic2)
结果:
#<class 'list'> [1, ['a', 'b', 'c'], 3, {'k1': 'v1', 'k2': 'v2'}]
dump、load
1.将对象转换成字符串写入到文件当中
import json
f = open('json_file.json','w')
dic = {'k1':'v1','k2':'v2','k3':'v3'}
json.dump(dic,f) #dump方法接收一个文件句柄,直接将字典转换成json字符串写入文件
f.close()
# json文件也是文件,就是专门存储json字符串的文件。
2.将文件中的字符串类型的字典转换成字典
import json
f = open('json_file.json')
dic2 = json.load(f) #load方法接收一个文件句柄,直接将文件中的json字符串转换成数据结构返回
f.close()
print(type(dic2),dic2)
ensure_ascii
:,当它为True的时候,所有非ASCII码字符显示为\uXXXX序列,只需在dump时将ensure_ascii设置为False即可,此时存入json的中文即可正常显示。
json.dump(dic,f,ensure_ascii=True)
结果:
{"k1": "v1", "\u5468\u9053\u9555": "\u715e\u7b14"}
json.dump(dic,f,ensure_ascii=False)
结果:
{"k1": "v1", "周道镕": "煞笔"}
separators
:分隔符,实际上是(item_separator, dict_separator)的一个元组,默认的就是(,,:);这表示dictionary内keys之间用“,”隔开,而KEY和value之间用“:”隔开。
json.dump(dic,f,separators=("*","+"))
结果:
{"k1"+"v1"*"k2"+"v2"*"k3"+"v3"}
sort_keys
:将数据根据keys的值进行排序。 剩下的自己看源码研究
dic = {'k3':'v3','k2':'v2','k1':'v1'}
json.dump(dic,f,sort_keys=True)
结果:
{"k1": "v1", "k2": "v2", "k3": "v3"}
dic = {'k3':'v3','k2':'v2','k1':'v1'}
json.dump(dic,f,sort_keys=False)
结果:
{"k1": "v1", "k2": "v2", "k3": "v3"}
json序列化存储多个数据到同一个文件中
对于json序列化,存储多个数据到一个文件中是有问题的,默认一个json文件只能存储一个json数据,但是也可以解决,举例说明:
对于json 存储多个数据到文件中
dic1 = {'name':'oldboy1'}
dic2 = {'name':'oldboy2'}
dic3 = {'name':'oldboy3'}
f = open('序列化',encoding='utf-8',mode='a')
json.dump(dic1,f)
json.dump(dic2,f)
json.dump(dic3,f)
f.close()
f = open('序列化',encoding='utf-8')
ret = json.load(f)
ret1 = json.load(f)
ret2 = json.load(f)
print(ret)
上边的代码会报错,解决方法:
dic1 = {'name':'oldboy1'}
dic2 = {'name':'oldboy2'}
dic3 = {'name':'oldboy3'}
f = open('序列化',encoding='utf-8',mode='a')
str1 = json.dumps(dic1)
f.write(str1+'\n')
str2 = json.dumps(dic2)
f.write(str2+'\n')
str3 = json.dumps(dic3)
f.write(str3+'\n')
f.close()
f = open('序列化',encoding='utf-8')
for line in f:
print(json.loads(line))
结果:
{'name': 'oldboy1'}
{'name': 'oldboy2'}
{'name': 'oldboy3'}
文件同是
1.2 pickle模块
pickle模块是将Python所有的数据结构以及对象等转化成bytes类型,然后还可以反序列化还原回去。
pickle模块是只能Python语言识别的序列化模块。如果把序列化模块比喻成全世界公认的一种交流语言,也就是标准的话,json就是像是英语,全世界(python,java,php,C,等等)都遵循这个标准。而pickle就是中文,只有中国人(python)作为第一交流语言。
既然只是Python语言使用,那么它支持Python所有的数据类型包括后面我们要讲的实例化对象等,它能将这些所有的数据结构序列化成特殊的bytes,然后还可以反序列化还原。使用上与json几乎差不多,也是两对四个方法。
用于网络传输:dumps、loads
用于文件写读:dump、load
dumps、loads
import pickle
dic = {'k1':'v1','k2':'v2','k3':'v3'}
str_dic = pickle.dumps(dic)
print(str_dic) # 类似bytes类型
结果:一串b'类似bytes
dic2 = pickle.loads(str_dic)
print(dic2) #字典
结果:
{'k1': 'v1', 'k2': 'v2', 'k3': 'v3'}
# 还可以序列化对象
import pickle
def func():
print(666)
ret = pickle.dumps(func)
print(ret,type(ret)) # b'\x80\x03c__main__\nfunc\nq\x00.' <class 'bytes'>
f1 = pickle.loads(ret) # f1得到 func函数的内存地址
f1() # 执行func函数
结果:
b'\x80\x03c__main__\nfunc\nq\x00.' <class 'bytes'>
666
dump、load
dic = {(1,2):'oldboy',1:True,'set':{1,2,3}}
f = open('pick序列化',mode='wb')
pickle.dump(dic,f)
f.close()
with open('pick序列化',mode='wb') as f1:
pickle.dump(dic,f1)
pickle序列化存储多个数据到一个文件中
dic1 = {'name':'oldboy1'}
dic2 = {'name':'oldboy2'}
dic3 = {'name':'oldboy3'}
f = open('pick多数据',mode='wb')
pickle.dump(dic1,f)
pickle.dump(dic2,f)
pickle.dump(dic3,f)
f.close()
f = open('pick多数据',mode='rb')
while True:
try:
print(pickle.load(f))
except EOFError:
break
f.close()
os.getcwd() 获取当前工作目录,即当前python脚本工作目录路径 ***
os.chdir("dirname") 改变当前脚本工作目录;相当于shell下cd **
os.curdir 返回当前目录: ('.') **
os.pardir 获取当前目录的父目录字符串名:('..') **
import os
path = "H:\Python代码文件\python24期\day08"
# 查看当前工作目录
retval = os.getcwd()
print("当前工作目录为 %s" % retval)
# 修改当前工作目录
os.chdir(path)
# 查看修改后的工作目录
retval = os.getcwd()
print("当前工作目录为 %s" % retval)
print(os.curdir)
print(os.pardir)
结果:
当前工作目录为 H:\Python代码文件\python24期\测试test
当前工作目录为 H:\Python代码文件\python24期\day08
.
..
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') 获取文件/目录信息 **
print(os.stat(r'H:\Python代码文件\python24期\测试test\test.py') ) #获取文件/目录信息 **
结果:
os.stat_result(st_mode=33206, st_ino=18014398509485740, st_dev=2290708642, st_nlink=1, st_uid=0, st_gid=0, st_size=35882, st_atime=1563693354, st_mtime=1563693354, st_ctime=1563693354)
os.path.abspath(path) 返回path规范化的绝对路径 ***
print(os.path.abspath(r"./test.py")) #返回path规范化的绝对路径 ***
结果:
H:\Python代码文件\python24期\测试test\test.py
os.path.split(path) 将path分割成目录和文件名二元组返回 ***
print(os.path.split(r"H:\Python代码文件\python24期\测试test\test.py"))
结果:
('H:\\Python代码文件\\python24期\\测试test', 'test.py')
os.path.dirname(path) 返回path的目录。其实就是os.path.split(path)的第一个元素 **
print(os.path.dirname(r"H:\Python代码文件\python24期\测试test\test.py"))
结果:
H:\Python代码文件\python24期\测试test
os.path.basename(path) 返回path最后的文件名。如果path以/或\结尾,那么就会返回空值,即os.path.split(path)的第二个元素。 **
print(os.path.basename(r"H:\Python代码文件\python24期\测试test\test.py"))
结果:
test.py
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(os.path.join('H:\Python代码文件\python24期\测试test',"abc"))
print(os.path.join("bbc",'H:\Python代码文件\python24期\测试test',"abc"))
结果:
H:\Python代码文件\python24期\测试test\abc
H:\Python代码文件\python24期\测试test\abc
os.path.getctime(path) 返回path所指向的文件或者目录的最后访问时间
os.path.getmtime(path) 返回path所指向的文件或者目录的最后访问时间
os.path.getatime(path) 返回path所指向的文件或者目录的最后修改时间 **
os.path.getsize(path) 返回path的大小(实际不准) ***
os.sep 输出操作系统特定的路径分隔符,win下为"\\",Linux下为"/" *
os.linesep 输出当前平台使用的行终止符,win下为"\r\n",Linux下为"\n"
os.pathsep 输出用于分割文件路径的字符串 win下为;,Linux下为: *
os.name 输出字符串指示当前使用平台。win->'nt'; Linux->'posix' *
# 和执行系统命令相关
os.system("bash command") 运行shell命令,直接显示 **
os.popen("bash command).read() 运行shell命令,获取执行结果 **
os.environ 获取系统环境变量 **
os.system方法是os模块最基础的方法,其它的方法一般在该方法基础上封装完成。
import os
os.system('cd /usr/local')
os.mkdir('aaa.txt)
import os
os.system('cd /usr/local && mkdir aaa.txt')
# 或者
os.system('cd /usr/local ; mkdir aaa.txt')
print(os.stat(r'H:\Python代码文件\python24期\测试test\test.py') ) #获取文件/目录信息 **
结果:
os.stat_result(st_mode=33206, st_ino=18014398509485740, st_dev=2290708642, st_nlink=1, st_uid=0, st_gid=0, st_size=35882, st_atime=1563693354, st_mtime=1563693354, st_ctime=1563693354)
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)是创建时间(详细信息参见平台的文档)。
重要:sys.path
: 获取指定模块搜索路径的字符串列表,可以将写好的模块放在得到的某个路径下,就可以在程序中import时正确找到。
import sys
print(sys.argv) #命令行参数List,第一个元素是程序本身路径,当前文件运行,执行脚本的时候可以携带参数,用处:可以远程登录输入用户名和密码
结果:
['H:/Python代码文件/python24期/测试test/test5.py']
# sys.exit(n) #退出程序,正常退出时exit(0),错误退出sys.exit(1)
# sys.version #获取Python解释程序的版本信息
# sys.path #返回模块的搜索路径,初始化时使用PYTHONPATH环境变量的值 *****
# sys.platform #返回操作系统平台名称 #win32
hashlib被称为摘要算法:
做加密和校验使用,其工作原理:它通过一个函数,把任意长度的数据按照一定规则转换为一个固定长度的数据串(通常用16进制的字符串表示).
我们在一个文件中存储用户的用户名和密码是不会是明文的,一般我们存储密码时都是以密文存储,比如:
123456加密后就是4665ace0eb5d3d6a2822a7c455587e47
章超印|4665ace0eb5d3d6a2822a7c455587e47
即使别人窃取你的密码文件,他也不会轻易的破解出密码.
我们以常见的摘要算法MD5为例,计算出一个字符串的MD5值:
import hashlib
md5 = hashlib.md5()
md5.update('123456'.encode('utf-8')) # 必须是bytes类型才能够进行加密
print(md5.hexdigest())
# 计算结果如下:
'e10adc3949ba59abbe56e057f20f883e'
# 验证:相同的bytes数据转化的结果一定相同
import hashlib
md5 = hashlib.md5()
md5.update('123456'.encode('utf-8'))
print(md5.hexdigest())
# 计算结果如下:
'e10adc3949ba59abbe56e057f20f883e'
# 验证:不相同的bytes数据转化的结果一定不相同
import hashlib
md5 = hashlib.md5()
md5.update('12345'.encode('utf-8'))
print(md5.hexdigest())
# 计算结果如下:
'827ccb0eea8a706c4c34a16891f84e7b'
上面就是普通的md5加密,非常简单,几行代码就可以了,但是这种加密级别是最低的,相对来说不很安全。虽然说hashlib加密是不可逆的加密方式,但也是可以破解的,那么他是如何做的呢?你看网上好多MD5解密软件,他们使用撞库的方式。他们会把常用的一些密码比如:123456,111111,以及他们的md5的值做成对应关系,类似于字典,
dic = {‘e10adc3949ba59abbe56e057f20f883e‘: 123456}
循环他们那定义的字典中的键和咱们生成的密文进行比较,比较成功后通过你的密文获取对应的密码。
所以针对刚才说的情况,我们有更安全的加密方式:加盐。
ret = hashlib.md5('章超印最帅'.encode('utf-8')) # 章超印最帅就是固定的盐
ret.update('a'.encode('utf-8'))
print(ret.hexdigest())
username = '章超印最帅'
ret = hashlib.md5(username[::2].encode('utf-8')) # 针对于每个账户,每个账户的盐都不一样
ret.update('a'.encode('utf-8'))
print(ret.hexdigest())
hahslib模块是一个算法集合,他里面包含很多种加密算法,刚才我们说的MD5算法是比较常用的一种加密算法,一般的企业用MD5就够用了。但是对安全要求比较高的企业,比如金融行业,MD5加密的方式就不够了,得需要加密方式更高的,比如sha系列,sha1,sha224,sha512等等,数字越大,加密的方法越复杂,安全性越高,但是效率就会越慢。
ret = hashlib.sha1()
ret.update('guobaoyuan'.encode('utf-8'))
print(ret.hexdigest())
#也可加盐
ret = hashlib.sha384(b'asfdsa')
ret.update('guobaoyuan'.encode('utf-8'))
print(ret.hexdigest())
# 也可以加动态的盐
ret = hashlib.sha384(b'asfdsa'[::2])
ret.update('guobaoyuan'.encode('utf-8'))
print(ret.hexdigest())
不过一般我们用到MD5加密就可以了。
将文件校验写在一个函数中
low版文件校验:
def func(file):
with open(file,mode='rb') as f1:
ret = hashlib.md5()
ret.update(f1.read())
return ret.hexdigest()
print(func('hashlib_file1'))
这样就可以计算此文件的MD5值,从而进行文件校验。但是这样写有一个问题,有什么问题?如果文件过大,全部读取出来直接就会撑爆内存的,所以我们要分段读取,那么分段读取怎么做呢?
hashlib还可以这样玩:
import hashlib
# 直接 update
md5obj = hashlib.md5()
md5obj.update('宝元 is a old driver'.encode('utf-8'))
print(md5obj.hexdigest()) # da525c66739e6baa8729332f8bae8e0f
# 分段update
md5obj = hashlib.md5()
md5obj.update('宝元 '.encode('utf-8'))
md5obj.update('is '.encode('utf-8'))
md5obj.update('a '.encode('utf-8'))
md5obj.update('old '.encode('utf-8'))
md5obj.update('driver'.encode('utf-8'))
print(md5obj.hexdigest()) # da525c66739e6baa8729332f8bae8e0f
# 结果相同
我们现在知道可以进行分段update后,我们就可以迭代的获取文件中的内容,现在来做一个高大上版文件校验
高大上版文件校验
校验Pyhton解释器的Md5值是否相同
import hashlib
def file_check(file_path):
with open(file_path,mode='rb') as f1:
md5 = hashlib.md5()
while 1:
content = f1.read(1024)
if content:
md5.update(content)
else:
return md5.hexdigest()
print(file_check('python-3.6.6-amd64.exe'))
在内置数据类型(dict、list、set、tuple)的基础上,collections模块还提供了几个额外的数据类型:Counter、deque、defaultdict、namedtuple和OrderedDict等。
1.namedtuple: 生成可以使用名字来访问元素内容的tuple
2.deque: 双端队列,可以快速的从另外一侧追加和推出对象
3.Counter: 计数器,主要用来计数
4.OrderedDict: 有序字典
5.defaultdict: 带有默认值的字典
我们知道tuple可以表示不变数据,例如,一个点的二维坐标就可以表示成:
p = (1, 2)
但是,看到(1, 2),很难看出这个tuple是用来表示一个坐标的。
这时,namedtuple就派上了用场:
from collections import namedtuple
Point = namedtuple('Point', ['x', 'y'])
p = Point(1, 2)
print(p)
结果:Point(x=1, y=2)
类似的,如果要用坐标和半径表示一个圆,也可以用namedtuple定义:
namedtuple('名称', [属性list]): # [属性list],(属性tuple),{属性set}
Circle = namedtuple('Circle', ['x', 'y', 'r'])
使用list存储数据时,按索引访问元素很快,但是插入和删除元素就很慢了,因为list是线性存储,数据量大的时候,插入和删除效率很低。
deque是为了高效实现插入和删除操作的双向列表,适合用于队列和栈:
from collections import deque
q = deque(['a', 'b', 'c']) #里面不管跟列表还是元组,还是集合,最终都变成了列表
#q = deque(('a', 'b', 'c')) #结果都一样
#q = deque({'a', 'b', 'c'}) #结果都一样
q.append('x')
q.appendleft('y')
q
deque(['y', 'a', 'b', 'c', 'x'])
deque除了实现list的append()和pop()外,还支持appendleft()和popleft(),这样就可以非常高效地往头部添加或删除元素。
使用dict时,Key是无序的。在对dict做迭代时,我们无法确定Key的顺序。
如果要保持Key的顺序,可以用OrderedDict:
from collections import OrderedDict
d = dict([('a', 1), ('b', 2), ('c', 3)]) # 另一种定义字典的方式
print(d)
# 结果:
{'a': 1, 'c': 3, 'b': 2}
od = OrderedDict([('a', 1), ('b', 2), ('c', 3)]) #里面不管跟列表还是元组,还是集合,只要只是两个值,最终都变成了字典
#od = OrderedDict([['a', 1], ('b', 2), {'c', 3}])
print(od)
# 结果:
OrderedDict([('a', 1), ('b', 2), ('c', 3)])
注意,OrderedDict的Key会按照插入的顺序排列,不是Key本身排序:
>>> od = OrderedDict()
>>> od['z'] = 1
>>> od['y'] = 2
>>> od['x'] = 3
>>> od.keys() # 按照插入的Key的顺序返回
['z', 'y', 'x']
有如下值集合 [11,22,33,44,55,66,77,88,99,90...],将所有大于 66 的值保存至字典的第一个key中,将小于 66 的值保存至第二个key的值中。
即: {‘k1‘: 大于66 , ‘k2‘: 小于66}
li = [11,22,33,44,55,77,88,99,90]
result = {}
for row in li:
if row > 66:
if 'key1' not in result:
result['key1'] = []
result['key1'].append(row)
else:
if 'key2' not in result:
result['key2'] = []
result['key2'].append(row)
print(result)
from collections import defaultdict
values = [11, 22, 33,44,55,66,77,88,99,90]
my_dict = defaultdict(list)
for value in values:
if value>66:
my_dict['k1'].append(value)
else:
my_dict['k2'].append(value)
使用dict时,如果引用的Key不存在,就会抛出KeyError。如果希望key不存在时,返回一个默认值,就可以用defaultdict:
from collections import defaultdict
dd = defaultdict(lambda: "")
dd['key1'] = 'abc'
# key1存在
print(dd['key1']) # key1存在,就返回对应的值.
dd['key2'] # key2不存在,返回你设定的默认值""空字符串
print(dd['key2'])
Counter类的目的是用来跟踪值出现的次数。它是一个无序的容器类型,以字典的键值对形式存储,其中元素作为key,其计数作为value。计数值可以是任意的Interger(包括0和负数)。Counter类和其他语言的bags或multisets很相似。
c = Counter('abcdeabcdabcaba')
print c
输出:Counter({'a': 5, 'b': 4, 'c': 3, 'd': 2, 'e': 1})
c = Counter([1,2,3,4,12,3,4,3,2,2])
print(c)
c = Counter({1,2,3,4,12,3,4,3,2,2}) #集合天然去重
print(c)
结果:Counter({1: 1, 2: 1, 3: 1, 4: 1, 12: 1})
标签:hashlib osi 不同的 平台 内存地址 批注 amd 并且 不可
原文地址:https://www.cnblogs.com/zhangchaoyin/p/11378825.html