3.1 容器类型
第2章我们介绍了Python中的基本数据类型,分别是整型、浮点型、字符串型以及布尔类型。在了解了基本数据类型后,我们便可以编写简单的Python代码,但想实现复杂的逻辑还是会稍显吃力。本节我们学习Python中的容器类型数据结构,它能让读者在编写复杂程序时更加游刃有余。
3.1.1 列表
列表(list)是一种有序容器,可以向其中添加或删除任意元素。在Python中,我们可以使用list方法创建一个空列表,也可以使用一对中括号来创建列表。因为中括号写起来更简便,所以通过中括号创建列表更为常见。示例代码如下:
列表数据类型是一种容器类型,列表中可以存放不同数据类型的值。上述代码中,l3列表中就存放了整型、浮点型、字符串型以及布尔类型的值。
容器类型变量中可以存放另一个容器类型变量,如列表中存放列表:
Python中提供了多种方法供我们轻松操作列表,并实现列表中元素的增、删、改、查。下面简单介绍列表的常用方法。
通过append方法可以向列表中添加元素,代码如下:
在Python中,append方法可以将任意元素添加到列表中,以此作为列表中的“一个”元素。注意,append方法不能一次性地向列表中添加多个元素。
一个有趣的想法是,我们通过append方法添加列表后,会产生什么结果?示例代码如下:
答案是会产生一个无限层的列表,这种列表通常没有实际作用。
除append方法外,我们还可以通过extend方法向列表中添加元素。extend方法只接收列表类型的值作为参数,该方法会将参数列表中的元素“拼接”到原始列表的尾部。示例代码如下:
现在,我们知道通过append方法与extend方法可以向列表中添加元素,那么如何获取列表中的元素呢?列表中的元素可以通过对应的下标获取,下标的起始值为0,代码如下:
下标可以是正数,也可以是负数,列表中的最后一个元素可以通过-1获取,倒数第二个元素可以通过-2获取,依此类推。示例代码如下:
除单纯使用下标获取单个元素外,我们还可以使用切片获取一部分元素。切片通过中括号括起,在中括号中填写开始下标与结束下标,两个下标间通过冒号分割。使用切片获取的元素会包含开始下标对应的元素,但不会包含结束下标对应的元素。示例代码如下:
上述代码使用切片获取了a列表中的一部分元素,下标1对应着a列表中的2,下标5对应着a列表中的6。因为切片返回的数据会包含开始下标对应的元素,但不会包含结束下标对应的元素,所以结果为[2,3,4,5]。
除可以获取元素外,下标还可以作为修改与删除列表元素的基本操作。示例代码如下:
上述代码展示了修改与删除列表中元素的操作。如果要修改列表中的元素,只需将新的值赋给列表中对应下标的元素即可,而删除列表中的元素可以使用两种不同的方式。第一种是通过del关键字直接删除列表中对应下标元素的值,第二种是通过remove方法实现删除效果。如果不知道要删除的元素在列表中的下标,使用remove方法更加简单,但remove方法只会删除列表中与要删除值匹配的第一个元素。
在很多情况下,我们需要对列表中的元素进行排序,此时可以使用sort方法实现排序效果。示例代码如下:
如果需要对列表中的每个元素都进行操作,则可以使用for循环。例如,判断列表中的元素是否为偶数,如果为偶数,则将其添加到新的列表中,代码如下:
3.1.2 元组
元组(tuple)同样是一种有序集合,它与列表非常相似,都可以通过下标、切片等方法取值;但与列表不同的是,元组一旦被初始化便不可修改其中的元素。在Python中,可以通过tuple方法或小括号的形式定义元组,因为元组元素具有不可变更的特性,所以元组在初始化时便会传入对应的值。示例代码如下:
元组中的元素无法修改,如果强行修改会抛出错误。示例代码如下:
报错信息表明,tuple对象不支持修改,但有时会出现让人困惑的代码,如下:
上述代码创建了t1与t2两个元组,将两个元组相加后,再赋值给t1,t1元组的内容发生了变化,为何会如此?
其实,原本的t1元组并没有发生变化,而是创建了新的t1元组,所以从最终效果上看,像是修改了t1元组本身。使用id方法可以获取对象的唯一标识,通过唯一标识则可以判断出不同的变量是否指向相同的对象。示例代码如下:
回顾2.1.1节,变量只是一张“便利贴”,便利贴贴在了具体的值上。在上述代码中,变量t1在一开始贴在了元组(1,2,3,4)上,经过累加操作后,变量t1贴在了新的元组上,而原本的元组(1,2,3,4)依旧存在且没有改变。
与列表相似,可以通过下标或切片的方法获取元组的值。示例代码如下:
因为元组不可改变的特性,所以元组对象没有提供修改、增加、删除等方法。
元组是容器类型对象,容器类型对象可以存放容器类型对象本身,那么元组中是否可以存放列表呢?当然可以,使用元组存放列表会出现一些有趣的现象,代码如下:
上述代码创建了元组t,元组t的第3个元素是一个列表。元组中的元素是不可修改的,但上述代码似乎对元组元素进行了修改,而且还修改成功了。
其实元组中的元素并没有被修改,修改的是元组列表中的元素,如图3.1所示。元组t中第3个元素为列表,列表中的元素是可以修改的,但元组依旧指向原本的列表,所以元组中的元素并没有改变。
图3.1
3.1.3 字典
字典(dict)是一种由键值对(key-value)构成的数据结构,其中键与值通过冒号分割,我们通过键可以快速查找到对应的值。在Python中,我们可以通过dict方法或花括号来构建字典。示例代码如下:
字典数据类型没有下标的概念,只可以通过键值获取字典中对应的值。字典的使用方法与列表类似,不同之处在于列表使用中括号填写的是列表下标,而字典使用中括号填写的是字典中的键值。示例代码如下:
向字典中添加新的元素或修改已存在的元素都需要通过键值来完成。例如,如果想修改字典中元素的值,那么需要先通过键值定位元素,再直接将新的值赋给该元素,代码如下:
删除字典中的某个元素可以使用del方法,但如果想要清空整个字典,则需要使用clear方法。示例代码如下:
清空字典的另一种方法是直接将空字典赋值给当前字典变量,与clear方法不同,原本字典中的值其实没有被删除,我们只是将字典变量“便利贴”贴到了新的字典对象上,通过id方法可以看出两者不同。示例代码如下:
字典获取数据依赖于键值,这要求字典中的键值不可重复以及不可变。不可重复很好理解,一个字典中不会存在多个相同的键值,如果存在,那么使用最新的键值。示例代码如下:
不可变的含义不太好理解,回顾3.1.2节中元组相关内容,元组就是不可变对象,而列表是可变对象。不可变如字面含义,对象的内容不可被改变,其中整型、浮点型、字符串型以及元组型都是不可变类型,都可以作为字典的键。
字典中的每个元素都具有键与值,通过for循环遍历字典时,默认只会获取字典元素中的键;如果想要获取键与值,则需要使用items方法。示例代码如下:
我们可以结合字典与列表构成更复杂的数据结构来实现更复杂的代码。例如,有一个字典d,具体的值为{'a':1,'b':1,'c':3,'d':4,'e':3,'f':1,'g':4},是否可以将具有相同值的键整理出来?代码如下:
在上述代码中,一开始定义了一个新的字典new_d,然后通过for循环遍历字典中的键与值,接着调用setdefault方法,该方法会返回某个键对应的值,如果当前字典中不存在这个键,则会将默认值作为该键对应的值并返回默认值。setdefault方法接收两个参数,第一个参数为键,第二个参数为默认值。
上述代码中,setdefault方法的具体使用方式为new_d.setdefault(v,[]),这表示先从new_d字典中获取键值为v的值,如果new_d字典中不存在该键,则将空列表设置为该键对应的值并返回空列表。
因为setdefault方法会返回列表,所以在该方法后,append方法紧接着将对应的值添加到相应的列表中,最终将字典d中具有相同值的键整合在了一起。
默认的字典是无序的,如果希望创建有序字典,则可以使用collections库(Python内置库)下的OrderedDict类创建有序字典。示例代码如下:
通过OrderedDict类创建的有序字典存放的元素是具有顺序的,其余功能与普通字典类似。OrderedDict类其实也是基于dict类实现的,这种方法被称为继承,关于继承的相关内容可以阅读3.3.2节。
3.1.4 集合
集合(set)具有如下两个重要特性。
(1)集合中的元素没有顺序。
(2)集合中不存在重复元素。
集合元素的无序性让集合无法像列表那样通过下标去获取对应的值,集合元素不可重复的特性可以让集合用于去除重复值的场景。
在Python中,可以通过set方法或花括号来创建集合,字典也是使用花括号创建的,但与字典不同,集合中的元素没有键与值的概念。此外,我们只可通过set方法创建空集合,因为使用空花括号会创建字典对象。
Python中提供了多种方法可以轻松操作集合,实现集合中元素的增、删、改、查。下面我们简单介绍这些方法。
首先,集合可以通过add或update方法添加元素,代码如下:
其次,还可以通过remove或discard方法删除集合中的元素。如果使用remove方法删除集合中不存在的元素,Python会抛出错误,因为remove方法只能删除存在于集合中的元素;而discard方法则不同,即使要删除的元素不存在于集合中,也不会发生错误。示例代码如下:
因为集合具有元素不可重复的特性,所以常用集合处理去重任务。例如,要去除列表中重复的元素,此时就可以先将列表转为集合后再转为列表,代码如下:
与其他容器类型的数据结构不同,集合除支持上述基本操作外,还支持集合间运算。
通过“&”运算符可以计算出两个集合的交集,代码如下:
类似地,通过“-”运算符可以计算出两个集合的差集,通过“|”运算符可以计算出两个集合的并集,通过“^”运算符可以计算出两个集合的对称差集。示例代码如下: