Python一行流:像专家一样写代码
上QQ阅读APP看本书,新人免费读10天
设备和账号都新为新人

容器数据类型

Python提供的容器数据类型可以高效地处理复杂的操作,同时十分易于使用。

列表

列表(list)是一种用于存储元素序列的容器类型。跟字符串不同的是,列表是可变类型——可以在运行时修改它们。可以通过一系列例子来描述列表数据类型,这也是最好的方式。

这段代码展示了如何用方括号创建一个列表,以及如何用三个整数元素填充它。你还会发现列表中可以存在重复元素。len()函数返回的是列表中的元素数量。

关键词:is

关键字is的作用是检查两个变量是否指向内存中的同一个对象,这可能会让Python新手感到困惑。清单1-7的代码检查了两个整数和两个列表是否在内存中指向同一个对象。

清单1-7:使用关键字is

如果你创建了两个列表——即使它们包含的元素是相同的——它们仍然会指向内存中两个不同的列表对象。修改其中一个列表并不会影响另一个列表。之所以说列表是可变的,正是因为你可以在创建列表之后对其进行修改。因此,如果你去检查它们在内存中是否指向相同的对象,结果会是False。不过,整数是不可变类型,所以不存在一个变量修改了其指向的对象,而影响到其他所有指向这个对象的变量的风险。原因是整数对象3就是不可修改的。试图修改的话只会创建出一个新的整数对象,旧的对象是不会改变的。

添加元素

Python提供了三种常见方法来为现有的列表添加元素:追加(append)、插入(insert)和列表连接。

这三种操作都会生成同样的列表[1,2,3,4],不过追加操作是最快的,因为它既不需要遍历列表以在正确的位置插入元素(insert就是这么做的),也不需要基于两个子列表去创建一个新列表(列表连接)。因此可以简单认为,只有想在列表非末尾的某个特定位置插入元素的时候,才需要用到insert。列表连接则可以用来连接两个任意长度的列表。注意还有第四种方式,extend(),它提供了一种快速的方式,一次把多个元素追加到指定列表中。

移除元素

通过使用remove(x)方法,可以很容易地从列表里删除一个元素x

该方法操作的是列表对象本身,而不是根据所做修改创建一个新的列表。在前面的代码示例中,我们创建了一个叫作l的列表对象,并通过删除一个元素的操作,在内存中直接修改了这个对象。这样可以避免为同样的列表数据创建冗余的副本,从而节约内存开销。

反转列表

可以使用list.reverse()方法来颠倒列表元素的顺序。

反转列表也会修改原来的列表对象,而不是去创建一个新的列表对象。

列表排序

使用list.sort()方法,可以给列表排序:

同样,列表排序也会修改原始列表对象,得到的结果是以升序方式排序的。包含字符串对象的列表会以字典升序的方式排序(从a到z)。排序函数一般会假设两个对象是可比较的,粗略来说,如果对于任意数据类型ab,可以计算a>b,Python就能对列表[a,b]进行排序。

列表元素的索引

可以使用list.index(x)方法,找出一个特定元素x在列表中的索引。

index(x) 方法会找出元素x 在列表中第一次出现的位置,并返回对应的索引。像其他主要的编程语言一样,Python为第一个位置分配的索引是0,为第i 个位置分配的索引是i-1。

堆栈

直观地讲,堆栈数据结构是以先进先出(FIFO)方式工作的。把它想象成一叠文件:把每份新文件放在现有的那叠文件上面,而当你在堆栈上工作的时候,每次都会从最顶上取出文件。在计算机科学中,堆栈依然是一种基本的数据结构,用于操作系统管理、算法、语法解析和回溯。

Python列表可以直观地作为堆栈使用,列表操作方法append()可以用于向栈中添加项目,pop()则可以弹出最近添加的项目。

由于列表的实现极有效率,通常没有必要引入外部堆栈库。

集合

集合数据类型是Python和其他众多编程语言的一种基本数据类型。流行的分布式计算语言(比如MapReduce或Apache Spark)甚至几乎只关注集合操作,作为其编程基元。所以到底什么是集合?集合(set)就是一组无序且唯一的元素。把这个定义的几个主要方面拆开来看一下。

一组元素

集合是类似列表或者元组的一组元素,集合可以由基本元素(整数、浮点数、字符串等)或者复杂元素(对象实例、元组)组成。不过,集合中所有的数据类型必须是可哈希的,也就是说每个元素必须有一个对应的哈希值。一个对象的哈希值会用于把这个对象跟其他对象进行比较,因此哈希值必须是永远不变的。我们看一下清单1-8,它检查了三个字符串的哈希值后,用这些字符串创建了一个集合。如果试图创建一些列表的集合,就会失败,因为列表是不可哈希的。

清单1-8:集合数据类型只允许包含可哈希的元素

可以创建字符串的集合,因为字符串是可哈希的。但是不能创建列表的集合,因为列表是不可哈希的。其原因是哈希值取决于元素的内容,但列表是可变的。如果你改变了列表数据,哈希值就也得变。由于可变数据类型都是不可哈希的,你也就不能把它们放到集合里。

无序

与列表不同,集合中的元素没有固定的顺序。不论以什么顺序把它们放到集合中,你永远也无法确定集合以什么顺序来存储这些元素。下面是一个例子:

先输入的是hero,但是解释器先打出的是enemy(显然,Python解释器是黑暗一方的)。注意,你的解析器可能会以另一种顺序打出这些集合元素。

唯一

集合中的所有元素都是唯一的。严格地说:集合中满足x!=y的两个值x,y,一定具有不同的哈希值,即hash(x)!=hash(y)。因为集合中的任意两个元素都是不同的,你也就不能创建一支由哈利·波特的克隆人组成的大军去对抗伏地魔:

无论你多少次把同样的值放入同一个集合中,集合只会存储这个值的一个实例,原因是这些英雄具有同样的哈希值,而每一个集合对同一个哈希值的元素只会包含一次。普通集合类型有一种扩展的类型,叫作多重集合(multiset),这种数据结构可以存储同一个值的多个实例,然而在实践中很少用到。相反,你会在几乎任何一个有意义的代码库中发现集合的运用——例如,对一组顾客的集合与一组来过某家商店的人计算交集,而得到一个新的集合,其中每个顾客都来过这家商店。

字典

字典是一种很有用的数据结构,用来存储键值对(key,value)。

可以通过指定方括号里的键名来读写对应的值:

使用keys()values()函数,可以获取字典中所有的键和值。

使用items()方法,可以以(key,value)元组的形式获取字典里的所有数据:

用这种方式,可以轻松地迭代遍历一个字典中的所有键与值,而不用去单独访问它们。

成员

使用关键字in,可以检查一个值是否在字典、列表或集合中(见清单1-9)。

清单1-9:使用关键字in

上面使用关键字in来检测整数值42是否在一个整数列表中➊,以及字符串“21”是否在一个字符串列表中➋。如果x出现在y中,我们就说xy的一个成员。

检测是否为集合的成员,比检测是否为列表的成员更快:为了检查一个元素x是否出现在列表y中,需要遍历整个列表,直到找到x或者全部遍历完全部元素。然而,集合的实现很像字典:要检测元素x是否出现在集合y中,Python内部只需要执行一个操作y[hash(x)],并且检查返回值是不是None就知道了。

列表和字典解析

列表解析是一项很受欢迎的Python特性,用于帮你快速创建和修改列表。形式可以简单写为[ 表达式+ 上下文]

表达式 告诉Python如何处理列表中的每个元素。

上下文 告诉Python选择哪些元素。

例如,在列表解析语句[x for x in range(3)]中,第一个部分x就是(恒等的)表达式,第二部分for x in range(3)是上下文,这句代码生成了列表[1,2,3]。示例中传给range()函数的参数会让它返回指定范围的整数值0、1和2。关于列表解析的另一个例子如下所示:

集合解析也跟列表解析类似,但创建的是一个集合而不是列表。