Skip to main content

Pywhio

官方 @ PywhiO. Python大数据, AI技术, 微服务, DRF+REACT前后端分离实践.

5 min read · March 28th 2020 (originally published at pywhio)

Python-Dict应用编程指南-上篇

阅读:-


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 的关系

1585321694717

2.2 创建字典基础语法

1.通过 dict()创建

>>> a = dict(one=1, two=2, three=3)

2.通过{}创建

>>> b = {‘one’: 1, ‘two’: 2, ‘three’: 3}

2.2.1 举例一:创建一个 dict{}

1585321844055

2.2.2 举例二、创建一个空 dict{},并赋值

1585321863662

2.3 嵌套字典:

嵌套字典是位于其他字典中的字典

1585321949702

2.3.1 举例一、创建一个嵌套字典

1585322032035

2.4 对哈希表执行操作

2.4.1 查询字典的元素

1585322057363

图 2 :访问字典

2.4.1.1 举例一、 如何访问字典的元素

  1. 访问字典的{key:value},{key:},{:value}

1585322274728

2.输入一个指定的 key,获得对应的 value

1585322308657

3,对字典进行遍历,逐行打印所有的 key

1585322332444

4、对字典进行遍历,逐行打印所有的 value

1585322432338 \

5.对字典进行遍历,逐行打印所有的{key:value}

1585322743776 \

2.4.2 更新值

2.4.2.1 可变序列

在 python 的数据结构中,字典继承了一种叫做 sequence 的协议,所以他是一种可变的 sequence(系列),他的意涵是,字典这种结构保存的 value 是可以进行修改的。

字典是可变的数据类型,您可以根据需要更新他们

1585322835099

图 3: 字典的可变序列

2.4.2.2 举例一、对字典的 value 重新赋值

1585322895429

2.4.3 删除字典中元素

1585322957525

2.4.3.1 举例:删除 dict{} 中元素

1585323041894

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 字典的类与实例方法

1585323598522

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

字典键的特性

  1. 不允许同一个键出现两次;

键必须不可变,所以可以用数字,字符串或元组充当,所以用列表就不行;

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 组建读取文件,代码如下:

1585323903404

输出数据格式如下:

1585323929350

使用字典生成式:

new_dict = dict((key, value) for key, value in row.items())

输出数据结构:

print(new_dict)

1585323945050

3 流转换

3.1 概述

因为 Dict{}是一种强大的内存数据结构,所以我们要通过一系列的练习来实现不同格式和 dict{} 之间的转换。主要的模型见下图。

1585340152498

图 3-1 格式转换

由于 Dict{} 特殊的 hash 结构,特别适合在内存中作为一个内存数据库来使用, 所以我们需要练习各种格式,转换为 Dict{}。

3.2 Dict 与 dataframe 转化

DataFrame 是一种二维(2 维)数据结构,由各种类型的列组成。它与 Python 字典非常相似,您甚至可以将字典转换为 pandas dataframe。

3.2.1 举例一:Dict 转换为 DF

1585340218312

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)

输出数据格式如下:

1585340284989

3.3.2 Csv 转 dict 案例

3.3.2.1 输入 csv 文件,文件数据格式如下:

1585340364098

3.3.2.2 读取文件:

代码:

with open(“测试数据库.csv”,‘r’) as f:

# print(f)

流穿越数据格式:

1585340385504

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)

流穿越数据格式:

1585340418346

Fieldnames 句柄数据格式:

1585340430278

3.3.2.4 遍历 csv_reader,输出数据格式如下:

代码:

for row in csv_reader:

print(row)

遍历后 DictReader 数据格式如下:

1585340460280

3.3.2.5 将 csv 组建 DictReader 数据格式转化为字典

使用字典生成式取出结果:

new_dict = dict((key, value) for key, value in row.items())

输出 new-divt 数据格式如下:

1585340474587

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

1585340550329

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)

1585340567400

3.5 Xml2dict

3.5.1 用例描述

3.5.1.1 输入数据分析 (I)

在这里,我们假设银行的交易记录是 XML 格式的数据,相关的组成结构见下图所显示:

1585340587104

图 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 的配置文件,用于配置需要提取的信息结构的字段。

1585340682532

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 文件的树形结构。

1585340707093

图 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

1585340807544

3.5.4.2 读取当前目录下文件

1585340827662

控制台输出如下:

1585340843304

3.5.4.3 对 xml 文件进行解析得到多个 list

1585340866103

数据格式输出如下: 1585340876875

3.5.4.4 将 list 转化为字典

代码:record = dict(zip(header, values))

数据格式如下:

1585340899392

3.5.4.5 Dict-hash 的应用

通过 dict-hash 选取想要的数据:

ticket_infofield = [‘交易时间’,‘交易序号’,‘客户名称’,‘交易类型’,‘交易网点’,‘操作员编号’,‘客户 id’,‘交易金额’]

dict -key 数据格式如下:

1585340933809

选取需要的数据:

1585340945887

输出数据格式:

1585340964473

分享到微博

Previous

RabbitMQ-Shovel的数据转移
Starter
MicroServ
Tutorials
Report
Blog