1. 序列化模块
什么是序列化呢?
序列化的本质就是将一种数据结构 (如字典, 列表) 等转换成一个特殊的序列 (字符串或者 bytes) 的过程就叫做序列化.
为什么要有序列化模块?
如果你写入文件中的字符串是一个序列化后的特殊的字符串, 那么当你从文件中读取出来, 是可以转化回原数据结构的.
作用及用途
序列化模块就是将一个常见的数据结构转化成一个特殊的序列, 并且这个特殊的序列还可以反解回去. 它的主要用途: 文件读写数据, 网络传输数据.
1.1 JSON 序列化(很重要)
不同语言都遵循 JSON 数据转化格式, 即不同语言都使用的特殊字符串.
JSON 序列化只支持部分 Python 数据结构: dict,list, tuple,str,int, float,True,False,None
JSON 模块
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 序列化
只能是 Python 语言遵循的一种数据转化格式, 只能在 python 语言中使用.
支持 Python 所有的数据类型包括实例化对象
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()
1.3 shelve 模块: 类似于字典的操作方式去操作特殊的字符串(了解即可)
2. os
os 模块是与操作系统交互的一个接口, 它提供的功能多与工作目录, 路径, 文件等相关.
2.1 当前执行这个 python 文件的工作目录相关的工作路径
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
.
..
2.2 文件夹相关
- os.makedirs('dirname1/dirname2') #可生成多层递归目录 ***
- os.removedirs('dirname1') #若目录为空, 则删除, 并递归到上一级目录, 如若也为空, 则删除, 依此类推 ***
- os.mkdir('dirname') #生成单级目录; 相当于 shell 中 mkdir dirname ***
- os.rmdir('dirname') #删除单级空目录, 若目录不为空则无法删除, 报错; 相当于 shell 中 rmdir dirname ***
- os.listdir('dirname') #列出指定目录下的所有文件和子目录, 包括隐藏文件, 并以列表方式打印 **
2.3 文件相关
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)
2.4 路径相关
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 的大小(实际不准) ***
2.5 操作系统相关(了解)
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 模块最基础的方法, 其它的方法一般在该方法基础上封装完成.
os 的 system 原理
system 函数可以将字符串转化成命令在服务器上运行; 其原理是每一条 system 函数执行时, 其会创建一个子进程在系统上执行命令行, 子进程的执行结果无法影响主进程;
上述原理会导致当需要执行多条命令行的时候可能得不到预期的结果;
- import os
- os.system('cd /usr/local')
- os.mkdir('aaa.txt)
上述程序运行后会发现 txt 文件并没有创建在 / usr/local 文件夹下, 而是在当前的目录下;
使用 system 执行多条命令
为了保证 system 执行多条命令可以成功, 多条命令需要在同一个子进程中运行;
- import os
- os.system('cd /usr/local && mkdir aaa.txt')
- # 或者
- os.system('cd /usr/local ; mkdir aaa.txt')
2.6 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)
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) 是创建时间(详细信息参见平台的文档).
3 sys
重要: 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
- 4 hashlib
hashlib 被称为摘要算法:
用途:
1. 加密
2. 文件一致性校验
做加密和校验使用, 其工作原理: 它通过一个函数, 把任意长度的数据按照一定规则转换为一个固定长度的数据串(通常用 16 进制的字符串表示).
使用的原因:
我们在一个文件中存储用户的用户名和密码是不会是明文的, 一般我们存储密码时都是以密文存储, 比如:
123456 加密后就是 4665ace0eb5d3d6a2822a7c455587e47
章超印 | 4665ace0eb5d3d6a2822a7c455587e47
即使别人窃取你的密码文件, 他也不会轻易的破解出密码.
hashlib 的特征以及使用要点:
bytes 类型数据 ---> 通过 hashlib 算法 ---> 固定长度的字符串
不同的 bytes 类型数据转化成的结果一定不同.
相同的 bytes 类型数据转化成的结果一定相同.
此转化过程不可逆.
普通加密:
(批注: 其实 MD5 算法相同的 bytes 数据转化的结果可以不相同, 不相同的 bytes 数据转化的结果也可以相同, 但是 MD5 的安全性还是很高)
我们以常见的摘要算法 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'))
上图来自于宝哥(感谢宝哥)
5 collections
一. collections 模块
在内置数据类型 (dict,list,set,tuple) 的基础上, collections 模块还提供了几个额外的数据类型: Counter,deque,defaultdict,namedtuple 和 OrderedDict 等.
1.namedtuple: 生成可以使用名字来访问元素内容的 tuple
2.deque: 双端队列, 可以快速的从另外一侧追加和推出对象
3.Counter: 计数器, 主要用来计数
4.OrderedDict: 有序字典
5.defaultdict: 带有默认值的字典
namedtuple
我们知道 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'])
- deque
使用 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(), 这样就可以非常高效地往头部添加或删除元素.
里面不管跟列表还是元组, 还是集合, 最终都变成了列表
OrderedDict
使用 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']
- defaultdict
有如下值集合 [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 (有点用的)
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})
来源: http://www.bubuko.com/infodetail-3162236.html