python中集合和字典的使用

  • Post author:
  • Post category:python



集合


集合set是装有独特值的无序“袋子”。一个简单的集合可以包含任何数据类型的值。如果有两个集合,则可以执行像联合、交集以及集合求差等标准集合运算。


创建集合


重中之重。创建集合非常简单。

>>> a_set = {1}①
>>> a_set

{1}

>>> type(a_set)

class “set”

>>> a_set = {1, 2}③
>>> a_set

{1, 2}

要创建只包含一个值的集合,仅需将该值放置于花括号之间。({})。

实际上,集合以 类 的形式实现,但目前还无须考虑这一点。

要创建多值集合,请将值用逗号分开,并用花括号将所有值包裹起来。

还可以 列表 为基础创建集合。

>>> a_list = ["a", "b", "mpilgrim", True, False, 42]
>>> a_set = set(a_list)①
>>> a_set

{“a”, False, “b”, True, “mpilgrim”, 42}

>>> a_list③

[“a”, “b”, “mpilgrim”, True, False, 42]

要从列表创建集合,可使用 set() 函数。(懂得如何实现集合的学究可能指出这实际上并不是调用某个函数,而是对某个类进行实例化。我保证在本书稍后的地方将会学到其中的区别。目前而言,仅需知道 set() 行为与函数类似,以及它返回一个集合。)

正如我之前提到的,简单的集合可以包括任何数据类型的值。而且,如我之前所提到的,集合是 无序的。该集合并不记得用于创建它的列表中元素的最初顺序。如果向集合中添加元素,它也不会记得添加的顺序。

初始的列表并不会发生变化。

还没有任何值?没有问题。可以创建一个空的集合。

>>> a_set = set()①
>>> a_set

set()

>>> type(a_set)

class “set”

>>> len(a_set)④

0

>>> not_sure = {}⑤
>>> type(not_sure)

class “dict”

要创建空集合,可不带参数调用 set() 。

打印出来的空集合表现形式看起来有点儿怪。也许,您期望看到一个 {} 吧 ?该符号表示一个空的字典,而不是一个空的集合。本章稍后您将学到关于字典的内容。

尽管打印出的形式奇怪,这 确实是 一个集合……

…… 同时该集合没有任何成员。

由于从 Python 2 沿袭而来历史的古怪规定,不能使用两个花括号来创建空集合。该操作实际创建一个空字典,而不是一个空集合。

修改集合

有两种方法可向现有集合中添加值: add() 方法和 update() 方法。

>>> a_set = {1, 2}
>>> a_set.add(4)①
>>> a_set

{1, 2, 4}

>>> len(a_set)②

3

>>> a_set.add(1)③
>>> a_set

{1, 2, 4}

>>> len(a_set)④

3

add() 方法接受单个可以是任何数据类型的参数,并将该值添加到集合之中。

该集合现在有三个成员了。

集合是装 唯一值 的袋子。如果试图添加一个集合中已有的值,将不会发生任何事情。将不会引发一个错误;只是一条空操作。

该集合 仍然 只有三个成员。

>>> a_set = {1, 2, 3}
>>> a_set

{1, 2, 3}

>>> a_set.update({2, 4, 6})①
>>> a_set②

{1, 2, 3, 4, 6}

>>> a_set.update({3, 6, 9}, {1, 2, 3, 5, 8, 13})③
>>> a_set

{1, 2, 3, 4, 5, 6, 8, 9, 13}

>>> a_set.update([10, 20, 30])④
>>> a_set

{1, 2, 3, 4, 5, 6, 8, 9, 10, 13, 20, 30}

update() 方法仅接受一个集合作为参数,并将其所有成员添加到初始列表中。其行为方式就像是对参数集合中的每个成员调用 add() 方法。

由于集合不能包含重复的值,因此重复的值将会被忽略。

实际上,可以带任何数量的参数调用 update() 方法。如果调用时传递了两个集合, update() 将会被每个集合中的每个成员添加到初始的集合当中(丢弃重复值)。

update() 方法还可接受一些其它数据类型的对象作为参数,包括列表。如果调用时传入列表,update() 将会把列表中所有的元素添加到初始集合中。

从集合中删除元素

有三种方法可以用来从集合中删除某个值。前两种,discard() 和 remove() 有细微的差异。

>>> a_set = {1, 3, 6, 10, 15, 21, 28, 36, 45}
>>> a_set

{1, 3, 36, 6, 10, 45, 15, 21, 28}

>>> a_set.discard(10)①
>>> a_set

{1, 3, 36, 6, 45, 15, 21, 28}

>>> a_set.discard(10)②
>>> a_set

{1, 3, 36, 6, 45, 15, 21, 28}

>>> a_set.remove(21)③
>>> a_set

{1, 3, 36, 6, 45, 15, 28}

>>> a_set.remove(21)④

Traceback (most recent call last): File “”, line 1, in KeyError: 21

discard() 接受一个单值作为参数,并从集合中删除该值。

如果针对一个集合中不存在的值调用 discard() 方法,它不进行任何操作。不产生错误;只是一条空指令。

remove() 方法也接受一个单值作为参数,也从集合中将其删除。

区别在这里:如果该值不在集合中,remove() 方法引发一个 KeyError 例外。

就像列表,集合也有个 pop() 方法。

>>> a_set = {1, 3, 6, 10, 15, 21, 28, 36, 45}
>>> a_set.pop()①

1

>>> a_set.pop()

3

>>> a_set.pop()

36

>>> a_set

{6, 10, 45, 15, 21, 28}

>>> a_set.clear()②
>>> a_set

set()

>>> a_set.pop()③

Traceback (most recent call last): File “”, line 1, in KeyError: “pop from an empty set”

pop() 方法从集合中删除某个值,并返回该值。然而,由于集合是无序的,并没有“最后一个”值的概念,因此无法控制删除的是哪一个值。它基本上是随机的。

clear() 方法删除集合中 所有 的值,留下一个空集合。它等价于 a_set = set(),该语句创建一个新的空集合,并用之覆盖a_set变量的之前的值。

试图从空集合中弹出某值将会引发 KeyError 例外。


常见集合操作


Python 的 集合 类型支持几种常见的运算。

>>> a_set = {2, 4, 5, 9, 12, 21, 30, 51, 76, 127, 195}
>>> 30 in a_set

True

>>> 31 in a_set

False

>>> b_set = {1, 2, 3, 5, 6, 8, 9, 12, 15, 17, 18, 21}
>>> a_set.union(b_set)②

{1, 2, 195, 4, 5, 6, 8, 12, 76, 15, 17, 18, 3, 21, 30, 51, 9, 127}

>>> a_set.intersection(b_set)③

{9, 2, 12, 5, 21}

>>> a_set.difference(b_set)④

{195, 4, 76, 51, 30, 127}

>>> a_set.symmetric_difference(b_set)⑤

{1, 3, 4, 6, 8, 76, 15, 17, 18, 195, 127, 30, 51}

要检测某值是否是集合的成员,可使用 in 运算符。其工作原理和列表的一样。

union() 方法返回一个新集合,其中装着 在两个 集合中出现的元素。

intersection() 方法返回一个新集合,其中装着 同时 在两个集合中出现的所有元素。

difference() 方法返回的新集合中,装着所有在a_set出现但未在b_set中的元素。

symmetric_difference() 方法返回一个新集合,其中装着所有 只在其中一个 集合中出现的元素。

这三种方法是对称的。


continued from the previous example

>>> b_set.symmetric_difference(a_set)①

{3, 1, 195, 4, 6, 8, 76, 15, 17, 18, 51, 30, 127}

>>> b_set.symmetric_difference(a_set) == a_set.symmetric_difference(b_set)②

True

>>> b_set.union(a_set) == a_set.union(b_set)③

True

>>> b_set.intersection(a_set) == a_set.intersection(b_set)④

True

>>> b_set.difference(a_set) == a_set.difference(b_set)⑤

False

a_set与b_set的对称差分 看起来 和b_set与a_set的对称差分不同,但请记住:集合是无序的。任何两个包含所有同样值(无一遗漏)的集合可认为是相等的。

而这正是这里发生的事情。不要被 Python Shell 对这些集合的输出形式所愚弄了。它们包含相同的值,因此是相等的。

对两个集合的 Union[并集]操作也是对称的。

对两个集合的 Intersection[交集]操作也是对称的。

对两个集合的 Difference[求差]操作不是对称的。这是有意义的;它类似于从一个数中减去另一个数。操作数的顺序会导致结果不同。

最后,有几个您可能会问到的问题。

>>> a_set = {1, 2, 3}
>>> b_set = {1, 2, 3, 4}
>>> a_set.issubset(b_set)①

True

>>> b_set.issuperset(a_set)②

True

>>> a_set.add(5)③
>>> a_set.issubset(b_set)

False

>>> b_set.issuperset(a_set)

False

a_set是b_set的子集— 所有a_set的成员均为b_set的成员。

同样的问题反过来说,b_set是a_set的超集,因为a_set的所有成员均为b_set的成员。

一旦向a_set添加一个未在b_set中出现的值,两项测试均返回 False 。

布尔上下文环境中的集合

可在 if 这样的 布尔类型上下文环境中 使用集合。

>>> def is_it_true(anything):

… if anything:

… print(“yes, it”s true”)

… else:

… print(“no, it”s false”)

>>> is_it_true(set())①

no, it”s false

>>> is_it_true({"a"})②

yes, it”s true

>>> is_it_true({False})③

yes, it”s true

在布尔类型上下文环境中,空集合为假值。

任何至少包含一个上元素的集合为真值。

任何至少包含一个上元素的集合为真值。元素的值无关紧要。


字典


字典是键值对的无序集合。向字典添加一个键的同时,必须为该键增添一个值。(之后可随时修改该值。) Python 的字典为通过键获取值进行了优化,而不是反过来。

☞Python 中的字典与 Perl 5 中的 hash [散列]类似。在 Perl 5 中,散列存储的变量总是以一个 % 符开头。在 Python 中,变量可以随意命名,而 Python 内部跟踪其数据类型。


创建字典


创建字典非常简单。其语法与 集合 的类似,但应当指定键值对而不是值。有了字典后,可以通过键来查找值。

>>> a_dict = {"server": "db.diveintopython3.org", "database": "mysql"}①
>>> a_dict

{“server”: “db.diveintopython3.org”, “database”: “mysql”}

>>> a_dict["server"]②

“db.diveintopython3.org”

>>> a_dict["database"]③

“mysql”

>>> a_dict["db.diveintopython3.org"]④

Traceback (most recent call last): File “”, line 1, in KeyError: “db.diveintopython3.org”

首先,通过将两个字典项指定给a_dict变量创建了一个新字典。每个字典项都是一组键值对,整个字典项集合都被大括号包裹在内。

“server” 为键,通过 a_dict[“server”] 引用的关联值为 “db.diveintopython3.org” 。

“database” 为键,通过 a_dict[“database”] 引用的关联值为 “mysql” 。

可以通过键获取值,但不能通过值获取键。因此 a_dict[“server”] 为 “db.diveintopython3.org”,而 a_dict[“db.diveintopython3.org”] 会引发例外,因为 “db.diveintopython3.org” 并不是键。


修改字典


字典没有预定义的大小限制。可以随时向字典中添加新的键值对,或者修改现有键所关联的值。继续前面的例子:

>>> a_dict

{“server”: “db.diveintopython3.org”, “database”: “mysql”}

>>> a_dict["database"] = "blog">>> a_dict

{“server”: “db.diveintopython3.org”, “database”: “blog”}

>>> a_dict["user"] = "mark">>> a_dict③

{“server”: “db.diveintopython3.org”, “user”: “mark”, “database”: “blog”}

>>> a_dict["user"] = "dora">>> a_dict

{“server”: “db.diveintopython3.org”, “user”: “dora”, “database”: “blog”}

>>> a_dict["User"] = "mark">>> a_dict

{“User”: “mark”, “server”: “db.diveintopython3.org”, “user”: “dora”, “database”: “blog”}

在字典中不允许有重复的键。对现有的键赋值将会覆盖旧值。

可随时添加新的键值对。该语法与修改现有值相同。

新字典项(键为 “user”,值为 “mark”)出现在中间。事实上,在第一个例子中字典项按顺序出现是个巧合;现在它们不按顺序出现同样也是个巧合。

对既有字典键进行赋值只会用新值替代旧值。

该操作会将 user 键的值改回 “mark” 吗?不会!仔细看看该键——有个大写的U出现在”User”中。字典键是区分大小写的,因此该语句创建了一组新的键值对,而不是覆盖既有的字典项。对你来说它们可能是一样的,但对于 Python 而言它们是完全不同的。


混合值字典




典并非只能用于字符串。字典的值可以是任何数据类型,包括整数、布尔值、任何对象,甚至是其它的字典。而且就算在同一字典中,所有的值也无须是同一类型,

您可根据需要混合匹配。字典的键要严格得多,可以是字符串、整数和其它一些类型。在同一字典中也可混合、匹配使用不同数据类型的键。

实际上,您已经在 your first Python program 见过一个将非字符串用作键的字典了。

SUFFIXES = {1000: [“KB”, “MB”, “GB”, “TB”, “PB”, “EB”, “ZB”, “YB”],

1024: [“KiB”, “MiB”, “GiB”, “TiB”, “PiB”, “EiB”, “ZiB”, “YiB”]}

让我们在交互式 shell 中剖析一下:

>>> SUFFIXES = {1000: ["KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"],

… 1024: [“KiB”, “MiB”, “GiB”, “TiB”, “PiB”, “EiB”, “ZiB”, “YiB”]}

>>> len(SUFFIXES)①

2

>>> 1000 in SUFFIXES②

True

>>> SUFFIXES[1000]

[“KB”, “MB”, “GB”, “TB”, “PB”, “EB”, “ZB”, “YB”]

>>> SUFFIXES[1024]

[“KiB”, “MiB”, “GiB”, “TiB”, “PiB”, “EiB”, “ZiB”, “YiB”]

>>> SUFFIXES[1000][3]⑤

“TB”

类似 列表 和 集合 ,len() 函数将返回字典中键的数量。

而且像列表和集合一样,可使用 in 运算符以测试某个特定的键是否在字典中。

1000 是 字典 SUFFIXES 的一个键;其值为一个 8 元素列表(确切地说,是 8 个字符串)。

同样, 1024 是字典 SUFFIXES 的键;其值也是一个 8 元素列表。

由于 SUFFIXES[1000] 是列表,可以通过它们的 0 基点索引来获取列表中的单个元素。

布尔上下文环境中的字典

空字典为假值;所有其它字典为真值。

可以在 if 这样的 布尔类型上下文环境中 使用字典。

>>> def is_it_true(anything):

… if anything:

… print(“yes, it”s true”)

… else:

… print(“no, it”s false”)

>>> is_it_true({})①

no, it”s false

>>> is_it_true({"a": 1})②

yes, it”s true

在布尔类型上下文环境中,空字典为假值。

至少包含一个键值对的字典为真值。



版权声明:本文为dirk2014原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。