1 背景介绍
Dict 是一种 python 内嵌的数据对象,他可以在内存中保存一个 tabluar 类型的数据结构,并且能够对数据进行快速的索引,这样一来可以表现出类似于一个内存数据库的作用,因此既有丰富的编程特性,可以极大的简化程序内的处理过程;另外 Dict 这种对象具有动态的特性,也就是说并不需要事先声明 dict 的数据结构,可以在运行时候对 Dict 的机构进行动态的改变,所以具有很好的灵活性。第三 Dict 可以非常简约的进行内存运算,可以节省内存的使用。
真是因为 Dict 强大的特点,所有可以有以下典型的应用场景。
1.多种数据之间转换的桥梁。 Dict 可以和 csv,xml,json, pandas DF 之前进行各种正确的转换。
2.在大数据微服务的应用下,需要在有限的机器上部署尽量多的计算单元(容器),这种情况下需要对内存非常精益的使用。Dict 是非常好的一种数据结构。
3.提供一个内存数据库的功能,对于海量数据实现 hash 索引的功能。
2 Dict 的基础语法讲解
2.1 什么是字典
哈希表或 Hashmap 是一种将键映射到其值对的数据结构类型

图 1:字典的 hash function
在字典中,key 和 value 的关系
2.2 创建字典基础语法
1.通过 dict()创建
>>> a = dict(one=1, two=2, three=3)
2.通过{}创建
>>> b = {‘one’: 1, ‘two’: 2, ‘three’: 3}

2.2.1 举例一:创建一个 dict{}
2.2.2 举例二、创建一个空 dict{},并赋值
2.3 嵌套字典:
嵌套字典是位于其他字典中的字典
2.3.1 举例一、创建一个嵌套字典
2.4 对哈希表执行操作
2.4.1 查询字典的元素
图 2 :访问字典
2.4.1.1 举例一、 如何访问字典的元素
- 访问字典的{key:value},{key:},{:value}
2.输入一个指定的 key,获得对应的 value
3,对字典进行遍历,逐行打印所有的 key
4、对字典进行遍历,逐行打印所有的 value
5.对字典进行遍历,逐行打印所有的{key:value}
2.4.2 更新值
2.4.2.1 可变序列
在 python 的数据结构中,字典继承了一种叫做 sequence 的协议,所以他是一种可变的 sequence(系列),他的意涵是,字典这种结构保存的 value 是可以进行修改的。
字典是可变的数据类型,您可以根据需要更新他们
图 3: 字典的可变序列
2.4.2.2 举例一、对字典的 value 重新赋值
2.4.3 删除字典中元素

2.4.3.1 举例:删除 dict{} 中元素
2.5 字典的通用方法:
以下方法为通用 Mapping Types 类型支持的操作(表达式),但不是 dict 类的操作方法
list(d):返回字典 key 组成的列表
len(d):返回字典元素个数
d[key]: 返回字典中 key 对应的 value
d[key] = value:设置 key 对应的值为 value
del d[key]:删除 key 对应的元素
key in d:判断 key 是否在字典 keys 中
key not in:判断 key 是否在字典 keys 中
iter(d) :返回字典 key 组成的迭代器,等同于 iter(d.keys()).
reversed(d):返回字典 key 组成迭代器的倒排,等同于 reversed(d.keys()).
2.5.1 举例一、取出字典中元素:
示例
>>> d = {“one”: 1, “two”: 2, “three”: 3, “four”: 4}
>>> for i in d:
… print(i)
…
one
two
three
Four
Key 已经存在以下操作位更新操作:
>>> d[‘four’] = 4.0
Key 不存在以下操作为增加操作:
>>> d[‘five’] = 5
>>> d
{‘one’: 1, ‘two’: 2, ‘three’: 3, ‘four’: 4.0, ‘five’: 5}
>>> ‘six’ in d
False
>>>
>>> ‘two’ in d.keys()
True
2.6 字典的类与实例方法
2.6.1 举例一、字典的 key 与 value:
q 示例
**>>> d = {"one": 1, "two": 2, "three": 3, "four": 4}**
**>>> d.get('one’)**
**1**
**>>> d.has_key('five')**
**Traceback (most recent call last):**
**File "<stdin>", line 1, in <module>**
**AttributeError: 'dict' object has no attribute 'has_key’**
**(python3 之后删除了 has_key 方法,用 k in d 表达式是替代)**
**>>> d.keys()**
**dict_keys(['one', 'two', 'three', 'four’])**
**>>> d.values()**
**dict_values([1, 2, 3, 4])**
**>>> d.pop('four')**
**4**
**>>> d**
**{'one': 1, 'two': 2, 'three': 3}**
**>>> d = dict.fromkeys(['one','two','three','four'], 1)**
**>>> d**
**{'one': 1, 'two': 1, 'three': 1, 'four': 1}**
2.6.2 举例二:遍历字典的键值
遍历字典键值常用:items()方法
**>>> d = {"one": 1, "two": 2, "three": 3, "four": 4}**
**>>> d.items()**
**dict_items([('one', 1), ('two', 2), ('three', 3), ('four', 4)])**
**>>> for k,v in d.items():**
**... print(k,'=>',v)**
**...**
**one => 1**
**two => 2**
**three => 3**
**four => 4**
字典键的特性
- 不允许同一个键出现两次;
键必须不可变,所以可以用数字,字符串或元组充当,所以用列表就不行;
2.7 字典生成式
2.7.1 新增-字典生成式主要应用场景
字典生成式,主要应用于,从一个可以迭代的对象中选取字段,按照指定方法生成 dict。
举例如下:
字典生成式:d = {key: value for (key, value) in iterable}
其中 iterable 是一个可迭代的对象,比如 list=[(‘name’,‘zhangsan’),(‘age’,‘11’),(‘phone’,‘a’)]
控制台输出 d :{‘phone’: ‘a’, ‘name’: ‘zhangsan’, ‘age’: ‘11’}
2.7.2 字典生成式-举例一-从列表生成字典
for 循环遍历列表,将列表中小元组的 key 和 value 取出,作为字典中的 key:value
list4 = [(‘name’,‘zhangsan’),(‘age’,‘11’),(‘phone’,‘a’)]
dict_1 = {key:value for key,value in list4}
print (dict_1)
{‘phone’: ‘a’, ‘name’: ‘zhangsan’, ‘age’: ‘11’}
2.7.3 字典生成式-举例二-只取 key
list4 = [(‘name’,‘zhangsan,lisi’),(‘age’,‘11,12’),(‘phone’,‘a,5’)]
dict_1 = {key for key,value in list4} print (dict_1)
输出:{‘age’, ‘name’, ‘phone’}
2.7.4 字典生成式-举例三-只取 value
list4 = [(‘name’,‘zhangsan,lisi’),(‘age’,‘11,12’),(‘phone’,‘a,5’)]
dict_1 = {value for key,value in list4} print (dict_1)
输出:{‘a,5’, ‘11,12’, ‘zhangsan,lisi’}
2.7.5 新增-dict 生成式的应用价值,应用场景
上述举例一、从可迭代 list 中取出数据,生成字典。
举例二、从列表中只取 key,用于根据需求进行流转换,及判断 key 是否存在。
举例三、从列表中只取 value,用于根据需求进行流转换,及进行数据拆分,从 dict 中取出单一的 value 值。
应用价值,使数据结构生成可供索引的{key:value}数据类型,可以通过 key 快速查询到 value。
应用场景,应用于,在实际需求中需要通过某指定字段,进行数据的判断合并拆分的情况,我们可以通过字典特性通过 key 迅速找到 value。
2.7.6 字典生成式-举例四-与 csv 组件复合应用
通过 csv 组建读取文件,代码如下:
输出数据格式如下:
使用字典生成式:
new_dict = dict((key, value) for key, value in row.items())
输出数据结构:
print(new_dict)
3 流转换
3.1 概述
因为 Dict{}是一种强大的内存数据结构,所以我们要通过一系列的练习来实现不同格式和 dict{} 之间的转换。主要的模型见下图。
图 3-1 格式转换
由于 Dict{} 特殊的 hash 结构,特别适合在内存中作为一个内存数据库来使用, 所以我们需要练习各种格式,转换为 Dict{}。
3.2 Dict 与 dataframe 转化
DataFrame 是一种二维(2 维)数据结构,由各种类型的列组成。它与 Python 字典非常相似,您甚至可以将字典转换为 pandas dataframe。
3.2.1 举例一:Dict 转换为 DF
3.3 Csv 2dict{}
3.3.1 Csv 转 dict 原理:
1.使用 csv 组件
reader(csvfile, dialect=‘excel’, **fmtparams)
参数说明:
csvfile,必须是支持迭代(Iterator)的对象,可以是文件(file)对象或者列表(list)对象,如果是文件对
象,打开时需要加”b”标志参数。
dialect,编码风格,默认为 excel 的风格,也就是用逗号(,)分隔,dialect 方式也支持自定义,通过调用 register_dialect 方法来注册,下文会提到。
fmtparam,格式化参数,用来覆盖之前 dialect 对象指定的编码风格。
2.csv-dict 读取方式:
with open(“工参数据库 5G.csv”,‘r’) as f:
csv.DictReader(f)
输出数据格式如下:
3.3.2 Csv 转 dict 案例
3.3.2.1 输入 csv 文件,文件数据格式如下:
3.3.2.2 读取文件:
代码:
with open(“测试数据库.csv”,‘r’) as f:
# print(f)
流穿越数据格式:
3.3.2.3 通过 csv 组件解析 csv 文件
代码:
csv_reader = csv.DictReader(f,fieldnames=fieldnames) #self._fieldnames = fieldnames # list of keys for the dict 以 list 的形式存放键名
print(csv_reader)
流穿越数据格式:
Fieldnames 句柄数据格式:
3.3.2.4 遍历 csv_reader,输出数据格式如下:
代码:
for row in csv_reader:
print(row)
遍历后 DictReader 数据格式如下:
3.3.2.5 将 csv 组建 DictReader 数据格式转化为字典
使用字典生成式取出结果:
new_dict = dict((key, value) for key, value in row.items())
输出 new-divt 数据格式如下:
3.4 Json2 dict{}
3.4.1 Json-dict 原理:
在 Python 中自带 json 库。通过 import json 导入。
在 json 模块有 2 个方法,
· loads():将 json 数据转化成 dict 数据
· dumps():将 dict 数据转化成 json 数据
· load():读取 json 文件数据,转成 dict 数据
· dump():将 dict 数据转化成 json 数据后写入 json 文件
3.4.2 dict 转 json
import json
dict = {}
dict['name'] = 'many'
dict['age'] = 10
dict['sex'] = 'male'
print(dict) # 输出:{'name': 'many', 'age': 10, 'sex': 'male'}
j = json.dumps(dict)
print(j) # 输出:{"name": "many", "age": 10, "sex": "male"}
3.4.3 Json 转 dict
j = ’{“id”: “007”, “name”: “007”, “age”: 28, “sex”: “male”, “phone”: “13000000000”, “email”: “123@qq.com”}’
print(type(j))
dict = json.loads(s=j)
3.5 Xml2dict
3.5.1 用例描述
3.5.1.1 输入数据分析 (I)
在这里,我们假设银行的交易记录是 XML 格式的数据,相关的组成结构见下图所显示:
图 4-1 XML 格式的交易清单的组成结构
从上图可见, 相关的 XML 的数据包含以下的组成部分。
1.XML 的 header 部分: 包含信息模型参考索引, 产生 xml 文件的营业网点名称, XML 中包含的交易清单的开始时间和结束时间。
2.交易清单的表头部分(信息结构的名称): 描述交易 ticket 的全部信息结构的名称,以 list 列表的方式来呈现(信息结构的名称在”value”部分进行表达)。
3.交易清单的数据部分(休息结构的取值):描述交易 ticket 的全部信息结构的取值,以 list 列表的方式来呈现(信息结构的取值在“value”部分进行表达)。
根据上面的格式,我们可以提供三个 xml 文件。
文件的命名为:
QLR2019020710-001.xml
QLR2019020710-002.xml
QLR2019020710-003.xml
关于输入数据的描述,参考以下文件。
3.5.1.2 XML 解析处理过程(P)
1,用户界面向处理组件传递参数,入参包括:
入参 1: 存放 xml 文件的文件路径,
入参 2:存放解析后 CSV 的文件路径。
2,处理组件接收入参以后, 首先根据入参 1:存放 xml 文件的文件路径,识别需要处理的 xml 文件,建立一个待解析的文件清单。
3、处理组件读取一个配置文件, ticket_infofield.py 配置文件,确定需要提取的信息结构。
4,处理组件提取第一个文件,根据文件的后缀名称确定为 xml 格式,就调用 xml 处理组件,首先识别出 xml 文件的 ticket_name 部分的信息结构取值,将相关的信息结构传入到一个 list 当中。
5,处理组件将 ticket_infofield.py 中的定义的需要提取的信息结构名字的列表(list),和当前 xml 文件中识别出来的 ticket_name 部分的信息结构(list)进行比较,如果后者包含前者,这说明文件可以解析,转入后续的环节;否则,则提示当前文件错误。
6,处理组件根据入参 2:存放解析后 CSV 的文件路径,打开一个 CSV 文件的句柄, CSV 文件的文件名和 xml 文件相同;
并根据 ticket_infofield.py 中的定义的需要提取的信息结构名字的列表(list)顺序,写入 CSV 的表头数据。
7,处理组件接下来。从当前的 xml 文件中识别出 ticket_data 部分的信息结构的取值, 根据并根据 ticket_infofield.py 中的定义的需要提取的信息结构名字的列表名字,匹配出需要提取的 ticket_data 数据,处理完一条 ticket 交易记录,写入步骤 6 中打开的文件句柄中,写入一行数据;直到把所有的行记录处理完毕。
7,当前的文件处理完毕以后, 处理组件会打开一个结果 list,记录本次的处理结果。包含 6 个信息结构,[process result, xml-file-size,input xml-path,output-csv-path,start time,end time],
其中,process result=0,处理成;=1,处理失败。
Xml-file-size 记录处理的 xml 文件的大小。
input xml-path: 输入 xml 文件的决对路径;
output-csv-path:输出 csv 文件的决对路径;
start time :开始处理 xml 文件时间
end time :生成 csv 文件的时间
8, 处理组件,遍历待处理文件清单,继续后续文件的处理,并生成返回值。
9, 全部文件处理完毕以后,整合所有文件的处理记录保存为一个 CSV 文件,其中包含 7 个字段。
[sequence id,process result, xml-file-size,input xml-path,output-csv-path,start time,end time],
其中 sequence id 为自增序列。
CSV 的文件名为 xml-handle-log-uuid.csv
存放路径,入参 2:存放解析后 CSV 的文件路径。
10、输出本次用例执行的结果。包括 三个信息结构
[process result, number of xml handled,handle-log-path]
Process result:本次 xml 解析的结果,0 成功, 1,失败, 2,部分成功。
number of xml handled:本次解析的 xml 文件的数量。
handle-log-path:本次解析的日志文件的决对路径。(步骤 9 总生成的文件)
3.5.1.3 ticket_infofield.py
ticket_infofield.py 是一个 python 的配置文件,用于配置需要提取的信息结构的字段。
3.5.1.4 返回数值
输出本次用例执行的结果。包括 三个信息结构
[process result, number of xml handled,handle-log-path]
Process result:本次 xml 解析的结果,0 成功, 1,失败, 2,部分成功
number of xml handled:本次解析的 xml 文件的数量。
handle-log-path:本次解析的日志文件的决对路径。(步骤 9 总生成的文件)
3.5.2 设计约束
1、Xml 解析使用组件
ElementTree
2、 Pthon 使用 python3
3, xml 文件解析以后,在内存中以 dict{} 的格式保存。
3.5.3 待解析 XML 文件的树形结构
借助上面的树形结构的概念,我们来看看银行的 ticket 交易清单的 XML 文件的树形结构。
图 4-3 银行 ticket 的 XML 树形结构
从上图可见, 我们将一个具体的交易清单记录封装在子节点 measurement 下。 在这个节点下,一共有三个字节点:
子节点 1: objecttype 用于描述这个数据结构在现实世界的对象名称。
子节点 2:ticket name 用于描述银行交易清单的表头结构(column field) 。
子节点 3: ticket data 用于记录多条具体的交易记录的数据。子节点三下面还有多个子节点, 子节点的数量和 ticket data 中包含的记录数相当。
从上面的描述中,聪明的你是否感觉到很奇怪,为什么要把 ticket name,和 ticket data 分离在不同的子节点中。 因为从现实的事件来看,ticket name 代表的是 key, 而 ticket data 代表的是 value。 大家直观的想法,是参考 fileheader 这个节点的表达方式,将 key ,和 value 放置在同一个节点中进行表达?
这是因为,在现实的情况中,可能会存在着很多条交易记录, 假如将(key,value )的结构在同一个节点中表达,那么会耗费很多的空间来保存 key 的信息,而这些信息是完全一致的,存在大量的冗余信息。
所以在这里,采用的是将 ticket name(key), ticket data(value) 进行分离保存的方案。 在这个方案中,压缩了 key 的保存空间,所以比较优势一些。当然,这种处理方案也存在一个缺点,就是在解码的时候,会增加一些障碍。而这正是 python 的优势,可以使用一些善巧的结构,例如 dict 和 set 来简洁的处理这种情况。
3.5.4 Xml 转 dict 复合应用举例
3.5.4.1 配置文件输入
输入待解析的 csv 表头 ticket_infofield
输入待解析的标签 input_data
3.5.4.2 读取当前目录下文件
控制台输出如下:
3.5.4.3 对 xml 文件进行解析得到多个 list
3.5.4.4 将 list 转化为字典
代码:record = dict(zip(header, values))
数据格式如下:
3.5.4.5 Dict-hash 的应用
通过 dict-hash 选取想要的数据:
ticket_infofield = [‘交易时间’,‘交易序号’,‘客户名称’,‘交易类型’,‘交易网点’,‘操作员编号’,‘客户 id’,‘交易金额’]
dict -key 数据格式如下:
选取需要的数据:
输出数据格式: