作者选择了 COVID-19 救援基金作为 Write for Donations计划的一部分接受捐款。
介绍
Python 3 有许多内置的数据结构,包括tuples、字典和列表,数据结构为我们提供了组织和存储数据的方式。
在本教程中,我们将通过收藏
模块中的三个类(LINK0
)来帮助您使用tuples、字典和列表。我们将使用namedtuples
来创建名称字段的tuples、defaultdict
来简要地将信息组合到字典中,以及deque
来高效地将元素添加到类似列表的对象的两侧。
对于本教程,我们将主要与我们需要修改的鱼类库存工作,因为鱼被添加到或从虚构的水族馆中删除。
前提条件
要充分利用本教程,建议您熟悉 tuple、字典和列表数据类型,无论是他们的语法,还是如何从中获取数据。
将命名字段添加到 Tuples
Python tuples 是元素的不可变或不可改变的顺序序列。Tuples 通常用于代表列数据;例如,来自 CSV 文件的行或来自 SQL 数据库的行。
个性化鱼类:
1("Sammy", "shark", "tank-a")
这个tuple由三个 string 元素组成。
虽然在某些方面有用,但这个标签并不清楚地表明它的每个字段代表了什么。实际上,元素0
是一个名称,元素1
是一个物种,元素2
是持有库。
鱼鱼场的解释:
name | species | tank |
---|---|---|
Sammy | shark | tank-a |
该表清楚地表明,Tuple的三个元素中每一个都有一个明确的含义。
从收藏
模块中namedtuple
允许您将明确的名称添加到一个tuple的每个元素中,以便在Python程序中明确这些含义。
让我们使用namedtuple
来生成一个明确命名鱼的每个元素的类:
1from collections import namedtuple
2
3Fish = namedtuple("Fish", ["name", "species", "tank"])
「從集合輸入 namedtuple」讓您的Python程式存取「namedtuple」工廠函數. 「namedtuple()」函數呼叫返回一個與名稱「Fish」有關的類別。
我们可以使用鱼
类来代表以前的鱼:
1sammy = Fish("Sammy", "shark", "tank-a")
2
3print(sammy)
如果我们运行此代码,我们会看到以下输出:
1[secondary_label Output]
2Fish(name='Sammy', species='shark', tank='tank-a')
sammy
是使用Fish
类来实例化的。
sammy
的字段可以通过其名称或使用传统的 tuple 索引访问:
1print(sammy.species)
2print(sammy[1])
如果我们运行这两个打印
呼叫,我们会看到以下输出:
1[secondary_label Output]
2shark
3shark
访问 .species
会返回与使用 [1]
访问 sammy
中的第二个元素相同的值。
从收藏
模块中使用namedtuple
使您的程序更易于阅读,同时保持一个tuple的重要属性(它们是不可变的和顺序)。
此外,namedtuple
工厂函数还为Fish
的实例添加了几种额外的方法。
使用 ._asdict()
将实例转换为字典:
1print(sammy._asdict())
如果我们运行打印
,你会看到输出如下:
1[secondary_label Output]
2{'name': 'Sammy', 'species': 'shark', 'tank': 'tank-a'}
在「sammy」上调用 `.asdict()' 会返回一个字典,将三个字段名称的每个名称与相应的值相符。
Python 版本超过 3.8 可能会以稍微不同的方式输出此行. 例如,您可能会看到一个OrderedDict
而不是这里所示的简单字典。
<$>[注]
**注:**在Python中,带有领先的低分的方法通常被视为私有
。(https://docs.python.org/3/library/collections.html#collections.namedtuple)(如 _asdict()
, ._make()
,._replace()
等),然而, 是公开的。
在字典中收集数据
通常在Python字典中收集数据是有用的。从收藏
模块中默认字典
可以帮助我们快速、简洁地在字典中汇集信息。
defaultdict
永远不会引出 KeyError
. 如果一个密钥不存在,那么 defaultdict
只会插入并返回一个位数值:
1from collections import defaultdict
2
3my_defaultdict = defaultdict(list)
4
5print(my_defaultdict["missing"])
如果我们运行此代码,我们将看到如下的输出:
1[secondary_label Output]
2[]
'defaultdict' 插入并返回一个位数值,而不是扔一个 'KeyError'. 在这种情况下,我们将位数值作为列表。
相反,常规字典会将KeyError
投放到缺少的密钥上:
1my_regular_dict = {}
2
3my_regular_dict["missing"]
如果我们运行此代码,我们将看到如下的输出:
1[secondary_label Output]
2Traceback (most recent call last):
3 File "<stdin>", line 1, in <module>
4KeyError: 'missing'
常规字典my_regular_dict
在尝试访问不存在的密钥时提出KeyError
。
defaultdict
的行为与常规字典不同,而不是在缺失的密钥上举起一个KeyError
,defaultdict
将无参数的位置值调用来创建一个新的对象,在这种情况下,list()
将创建一个空的列表。
继续我们虚构的水族馆示例,让我们假设我们有一个代表水族馆库存的鱼列表:
1fish_inventory = [
2 ("Sammy", "shark", "tank-a"),
3 ("Jamie", "cuttlefish", "tank-b"),
4 ("Mary", "squid", "tank-a"),
5]
水族馆里有三条鱼,它们的名字、物种和持有箱在这三只鱼上都记载着。
我们的目标是根据坦克来组织我们的库存,我们想要知道每个坦克中存在的鱼类清单,换句话说,我们想要一个字典,将坦克-a
地图到Sammy
,Mary
和tank-b
到Jamie
。
我们可以使用默认字符号
来按坦克组合鱼类:
1from collections import defaultdict
2
3fish_inventory = [
4 ("Sammy", "shark", "tank-a"),
5 ("Jamie", "cuttlefish", "tank-b"),
6 ("Mary", "squid", "tank-a"),
7]
8fish_names_by_tank = defaultdict(list)
9for name, species, tank in fish_inventory:
10 fish_names_by_tank[tank].append(name)
11
12print(fish_names_by_tank)
运行此代码,我们会看到以下输出:
1[secondary_label Output]
2defaultdict(<class 'list'>, {'tank-a': ['Sammy', 'Mary'], 'tank-b': ['Jamie']})
「fish_names_by_tank」被声明为「默认字符号」,默认时将list()
插入而不是KeyError
。因为这保证了fish_names_by_tank
中的每个键都将指向list
,我们可以自由地呼叫.append()
,以便在每个坦克列表中添加名称。
Defaultdict
在这里帮助你,因为它减少了意想不到的KeyErrors
的可能性。减少意想不到的KeyErrors
意味着你的程序可以写得更清晰,并且有更少的行。
没有默认命令
,为
循环体可能看起来更像这样:
1[label More Verbose Example Without defaultdict]
2...
3
4fish_names_by_tank = {}
5for name, species, tank in fish_inventory:
6 if tank not in fish_names_by_tank:
7 fish_names_by_tank[tank] = []
8 fish_names_by_tank[tank].append(name)
仅使用常规字典(而不是默认字典
)意味着for
循环体必须在fish_names_by_tank
中始终检查给定的坦克
是否存在。
在填充字典时,Defaultdict可以帮助削减锅炉板代码,因为它从不提出KeyError
。
使用 deque 有效地将元素添加到收藏的任何一侧
Python 可以不断地附加到列表(列表的长度对附加所需的时间没有影响),但在列表的开始时插入可能会更慢 - 随着列表的增加,需要的时间会增加。
在 Big O 标注方面,附加到列表是一个恒定的时间 O(1)
操作。
<$>[注]
注: 软件工程师经常使用所谓的大O
符号来衡量程序的性能.当输入的大小对执行程序所需的时间没有影响时,它被称为在恒定时间或O(1)
(Big O of 1
)中运行。
有时,输入的大小会直接影响运行程序所需的时间。例如,插入Python列表的开始速度越慢,列表中的元素越多。
一般而言,O(1)
程序比O(n)
程序更快。
我们可以在Python列表的开头插入:
1favorite_fish_list = ["Sammy", "Jamie", "Mary"]
2
3# O(n) performance
4favorite_fish_list.insert(0, "Alice")
5
6print(favorite_fish_list)
如果我们运行以下操作,我们将看到如下结果:
1[secondary_label Output]
2['Alice', 'Sammy', 'Jamie', 'Mary']
列表中的.insert(index, object)
方法允许我们在favorite_fish_list
开始时插入Alice
。值得注意的是,在列表开始时插入具有O(n)
性能。
从收藏
模块中deque
(发音deck
)是一个类似列表的对象,允许我们在序列的开始或结束时以恒定时间(‘O(1)’)的性能插入项目。
插入一个项目在一个deque
的开始:
1from collections import deque
2
3favorite_fish_deque = deque(["Sammy", "Jamie", "Mary"])
4
5# O(1) performance
6favorite_fish_deque.appendleft("Alice")
7
8print(favorite_fish_deque)
运行此代码,我们将看到以下输出:
1[secondary_label Output]
2deque(['Alice', 'Sammy', 'Jamie', 'Mary'])
我们可以使用先前存在的元素集合来实例化一个deque
,在这种情况下是三种最喜欢的鱼类名称列表。称呼favorite_fish_deque
的附属左
方法允许我们在我们的集合开始时以O(1)
的性能插入一个项目。
<$>[注]
**注:**虽然deque
比列表更有效地将条目添加到序列的开始,但deque
不会比列表更有效地执行所有操作。例如,在deque
中访问随机项目具有O(n)
性能,但访问列表中的随机项目具有O(1)
性能。当重要的是快速插入或删除集合的两侧元素时,使用deque
。
结论
收藏
模块是Python标准库的强大组成部分,允许您简洁、高效地处理数据。本教程涵盖了收藏
模块提供的三个类别,包括namedtuple
,defaultdict
和deque
。
从这里,您可以使用收藏
模块的文档(https://docs.python.org/3/library/collections.html#module-collections)来了解更多关于其他可用的类和实用程序。