CH04_列表-元组-字典-集合
CH04_列表-元组-字典-集合
本章目标
- 掌握列表(List)的运用
- 掌握元组(Tuple)的运用
- 掌握字典(Dict)的运用
- 掌握集合(Set)的运用
python序列概述
所谓序列,指的是一块可存放多个值的连续内存空间,这些值按一定顺序排列,可通过每个值所在位置的编号(称为索引)访问它们。
为了更形象的认识序列,可以将它看做是一家旅店,那么店中的每个房间就如同序列存储数据的一个个内存空间,每个房间所特有的房间号就相当于索引值。也就是说,通过房间号(索引)我们可以找到这家旅店(序列)中的每个房间(内存空间)。
在 Python 中,序列类型包括字符串、列表、元组、集合和字典,这些序列支持以下几种通用的操作,但比较特殊的是,集合和字典不支持索引、切片、相加和相乘操作。
Python 序列(Sequence)是指按特定顺序依次排列的一组数据,它们可以占用一块连续的内存,也可以分散到多块内存中。Python 中的序列类型包括列表(list)、元组(tuple)、字典(dict)和集合(set)。
在 Python 编程中,我们既需要独立的变量来保存一份数据,也需要序列来保存大量数据。
列表(list)和元组(tuple)比较相似,它们都按顺序保存元素,所有的元素占用一块连续的内存,每个元素都有自己的索引,因此列表和元组的元素都可以通过索引(index)来访问。它们的区别在于:列表是可以修改的,而元组是不可修改的。
字典(dict)和集合(set)存储的数据都是无序的,每份元素占用不同的内存,其中字典元素以 key-value
的形式保存。
字符串也是一种常见的序列,它也可以直接通过索引访问字符串内的字符。
序列索引
序列中,每个元素都有属于自己的编号(索引)。从起始元素开始,索引值从 0 开始递增,如图 1 所示。
除此之外,Python 还支持索引值是负数,此类索引是从右向左计数,换句话说,从最后一个元素开始计数,从索引值 -1 开始,如图 2 所示。
注意,在使用负值作为列序中各元素的索引值时,是从 -1 开始,而不是从 0 开始。
无论是采用正索引值,还是负索引值,都可以访问序列中的任何元素。以字符串为例,访问“广创科技教育”的首元素和尾元素,可以使用如下的代码:
1 | str="广创科技教育" |
输出结果为:
1 | 广 == 广 |
序列切片
切片操作是访问序列中元素的另一种方法,它可以访问一定范围内的元素,通过切片操作,可以生成一个新的序列。
序列实现切片操作的语法格式如下:
1 | sname[start : end : step] |
其中,各个参数的含义分别是:
- sname:表示序列的名称;
- start:表示切片的开始索引位置(包括该位置),此参数也可以不指定,会默认为 0,也就是从序列的开头进行切片;
- end:表示切片的结束索引位置(不包括该位置),如果不指定,则默认为序列的长度;
- step:表示在切片过程中,隔几个存储位置(包含当前位置)取一次元素,也就是说,如果 step 的值大于 1,则在进行切片去序列元素时,会“跳跃式”的取元素。如果省略设置 step 的值,则最后一个冒号就可以省略。
例如,对字符串“广创科技教育”进行切片:
1 | str="广创科技教育" |
运行结果为:
1 | 广创 |
序列相加
Python 中,支持两种类型相同的序列使用“+”运算符做相加操作,它会将两个序列进行连接,但不会去除重复的元素。
1 | 这里所说的“类型相同”,指的是“+”运算符的两侧序列要么都是列表类型,要么都是元组类型,要么都是字符串。 |
例如,前面章节中我们已经实现用“+”运算符连接 2 个(甚至多个)字符串,如下所示:
1 | str="https://os-guangchuang.gitee.io/note/" |
输出结果为:
1 | 广创科技教育:https://os-guangchuang.gitee.io/note/ |
序列相乘
Python 中,使用数字 n 乘以一个序列会生成新的序列,其内容为原来序列被重复 n 次的结果。例如:
1 | str="广创科技教育" |
输出结果为:
1 | 广创科技教育广创科技教育广创科技教育 |
比较特殊的是,列表类型在进行乘法运算时,还可以实现初始化指定长度列表的功能。例如如下的代码,将创建一个长度为 5 的列表,列表中的每个元素都是 None,表示什么都没有。
1 | #列表的创建用 [],后续讲解列表时会详细介绍 |
输出结果为:
1 | [None, None, None, None, None] |
检查元素是否包含在序列中
Python 中,可以使用 in 关键字检查某元素是否为序列的成员,其语法格式为:
1 | value in sequence |
其中,value 表示要检查的元素,sequence 表示指定的序列。
例如,检查字符‘教’是否包含在字符串“广创科技教育”中,可以执行如下代码:
1 | str="广创科技教育" |
运行结果为:
1 | True |
和 in 关键字用法相同,但功能恰好相反的,还有 not in 关键字,它用来检查某个元素是否不包含在指定的序列中,比如说:
1 | str="广创科技教育" |
运行结果为:
1 | False |
和序列相关的内置函数
Python提供了几个内置函数(表 3 所示),可用于实现与序列相关的一些常用操作。
这里给大家给几个例子:
1 | str="c.biancheng.net" |
输出结果为:
1 | u |
列表List
创建列表
在 Python 中,创建列表的方法可分为两种,下面分别进行介绍。
1.使用【】创建列表
使用[ ]
创建列表后,一般使用=
将它赋值给某个变量,具体格式如下:
1 | listname = [element1 , element2 , element3 , ... , elementn] |
其中,listname 表示变量名,element1 ~ elementn 表示列表元素。
例如,下面定义的列表都是合法的:
1 | num = [1, 2, 3, 4, 5, 6, 7] |
另外,使用此方式创建列表时,列表中元素可以有多个,也可以一个都没有,例如:
1 | emptylist = [ ] |
2.使用list()函数创建列表
除了使用[ ]
创建列表外,Python 还提供了一个内置的函数 list(),使用它可以将其它数据类型转换为列表类型。例如:
1 | #将字符串转换成列表 |
运行结果:
1 | ['h', 'e', 'l', 'l', 'o'] |
访问列表元素
列表是 Python 序列的一种,我们可以使用索引(Index)访问列表中的某个元素(得到的是一个元素的值),也可以使用切片访问列表中的一组元素(得到的是一个新的子列表)。
使用索引访问列表元素的格式为:
1 | listname[i] |
其中,listname 表示列表名字,i 表示索引值。列表的索引可以是正数,也可以是负数。
使用切片访问列表元素的格式为:
1 | listname[start : end : step] |
其中,listname 表示列表名字,start 表示起始索引,end 表示结束索引,step 表示步长。
1 | url = list("https://os-guangchuang.gitee.io/note/") |
运行结果:
1 | p |
删除列表
对于已经创建的列表,如果不再使用,可以使用del
关键字将其删除。
实际开发中并不经常使用 del 来删除列表,因为 Python 自带的垃圾回收机制会自动销毁无用的列表,即使开发者不手动删除,Python 也会自动将其回收。
del 关键字的语法格式为:
1 | del listname |
Python 删除列表实例演示:
1 | intlist = [1, 45, 8, 34] |
运行结果:
1 | [1, 45, 8, 34] |
list列表添加元素
1.使用“+”运算符连接
1 | language = ["Python", "C++", "Java"] |
运行结果:
1 | language = ['Python', 'C++', 'Java'] |
从运行结果可以发现,使用+
会生成一个新的列表,原有的列表不会被改变。
2.使用append()方法添加
append() 方法用于在列表的末尾追加元素,该方法的语法格式如下:
1 | listname.append(obj) |
其中,listname 表示要添加元素的列表;obj 表示到添加到列表末尾的数据,它可以是单个元素,也可以是列表、元组等。
请看下面的演示:
1 | language = ['Python', 'C++', 'Java'] |
运行结果:
1 | ['Python', 'C++', 'Java', 'PHP'] |
可以看到,当给 append() 方法传递列表或者元组时,此方法会将它们视为一个整体,作为一个元素添加到列表中,从而形成包含列表和元组的新列表。
3.使用extend()方法添加
extend() 和 append() 的不同之处在于:extend() 不会把列表或者元祖视为一个整体,而是把它们包含的元素逐个添加到列表中。
extend() 方法的语法格式如下:
1 | listname.extend(obj) |
其中,listname 指的是要添加元素的列表;obj 表示到添加到列表末尾的数据,它可以是单个元素,也可以是列表、元组等,但不能是单个的数字。
1 | l = ['Python', 'C++', 'Java'] |
运行结果:
1 | ['Python', 'C++', 'Java', 'C'] |
使用insert()方法插入
append() 和 extend() 方法只能在列表末尾插入元素,如果希望在列表中间某个位置插入元素,那么可以使用 insert() 方法。
insert() 的语法格式如下:
1 | listname.insert(index , obj) |
其中,index 表示指定位置的索引值。insert() 会将 obj 插入到 listname 列表第 index 个元素的位置。
当插入列表或者元祖时,insert() 也会将它们视为一个整体,作为一个元素插入到列表中,这一点和 append() 是一样的。
请看下面的演示代码:
1 | l = ['Python', 'C++', 'Java'] |
输出结果:
1 | ['Python', 'C', 'C++', 'Java'] |
提示,insert() 主要用来在列表的中间位置插入元素,如果你仅仅希望在列表的末尾追加元素,那我更建议使用 append() 和 extend()。
list列表删除元素
在 Python 列表中删除元素主要分为以下 3 种场景:
- 根据目标元素所在位置的索引进行删除,可以使用 del 关键字或者 pop() 方法;
- 根据元素本身的值进行删除,可使用列表(list类型)提供的 remove() 方法;
- 将列表中所有元素全部删除,可使用列表(list类型)提供的 clear() 方法。
1.del: 根据索引键删除元素
del 是 Python 中的关键字,专门用来执行删除操作,它不仅可以删除整个列表,还可以删除列表中的某些元素。
del 可以删除列表中的单个元素,格式为:
1 | del listname[index] |
其中,listname 表示列表名称,index 表示元素的索引值。
del 也可以删除中间一段连续的元素,格式为:
1 | del listname[start : end] |
其中,start 表示起始索引,end 表示结束索引。del 会删除从索引 start 到 end 之间的元素,不包括 end 位置的元素。
【示例】使用 del 删除单个列表元素:
1 | lang = ["Python", "C++", "Java", "PHP", "Ruby", "MATLAB"] |
运行结果:
[‘Python’, ‘C++’, ‘PHP’, ‘Ruby’, ‘MATLAB’]
[‘Python’, ‘C++’, ‘PHP’, ‘MATLAB’]
【示例】使用 del 删除一段连续的元素:
1 | lang = ["Python", "C++", "Java", "PHP", "Ruby", "MATLAB"] |
运行结果:
[‘Python’, ‘Ruby’, ‘MATLAB’]
[‘Python’, ‘C#’, ‘Go’]
2.pop(): 根据索引键删除元素
Python pop() 方法用来删除列表中指定索引处的元素,具体格式如下:
1 | listname.pop(index) |
其中,listname 表示列表名称,index 表示索引值。如果不写 index 参数,默认会删除列表中的最后一个元素,类似于数据结构中的“出栈”操作。
pop() 用法举例:
1 | nums = [40, 36, 89, 2, 36, 100, 7] |
运行结果:
[40, 36, 89, 36, 100, 7]
[40, 36, 89, 36, 100]
大部分编程语言都会提供和 pop() 相对应的方法,就是 push(),该方法用来将元素添加到列表的尾部,类似于数据结构中的“入栈”操作。但是 Python 是个例外,Python 并没有提供 push() 方法,因为完全可以使用 append() 来代替 push() 的功能。
3.remove(): 根据元素值删除元素
除了 del 关键字,Python 还提供了 remove() 方法,该方法会根据元素本身的值来进行删除操作。
需要注意的是,remove() 方法只会删除第一个和指定值相同的元素,而且必须保证该元素是存在的,否则会引发 ValueError 错误。
remove() 方法使用示例:
1 | nums = [40, 36, 89, 2, 36, 100, 7] |
运行结果:
1 | [40, 89, 2, 36, 100, 7] |
最后一次删除,因为 78 不存在导致报错,所以我们在使用 remove() 删除元素时最好提前判断一下。
4.clear(): 清空列表
Python clear() 用来删除列表的所有元素,也即清空列表,请看下面的代码:
1 | url = list("https://os-guangchuang.gitee.io/note/") |
运行结果:
1 | [] |
list列表修改元素
Python 提供了两种修改列表(list)元素的方法,你可以每次修改单个元素,也可以每次修改一组元素(多个)。
1.修改单个元素
1 | nums = [40, 36, 89, 2, 36, 100, 7] |
运行结果:
[40, 36, -26, 2, -66.2, 100, 7]
2.修改一组元素
Python 支持通过切片语法给一组元素赋值。在进行这种操作时,如果不指定步长(step 参数),Python 就不要求新赋值的元素个数与原来的元素个数相同;这意味,该操作既可以为列表添加元素,也可以为列表删除元素。
下面的代码演示了如何修改一组元素的值:
1 | nums = [40, 36, 89, 2, 36, 100, 7] |
运行结果:
[40, 45.25, -77, -52.5, 36, 100, 7]
如果对空切片(slice)赋值,就相当于插入一组新的元素:
1 | nums = [40, 36, 89, 2, 36, 100, 7] |
运行结果:
[40, 36, 89, 2, -77, -52.5, 999, 36, 100, 7]
使用切片语法赋值时,Python 不支持单个值,例如下面的写法就是错误的:
1 | nums[4: 4] = -77 |
但是如果使用字符串赋值,Python 会自动把字符串转换成序列,其中的每个字符都是一个元素,请看下面的代码:
1 | s = list("Hello") |
运行结果:
[‘H’, ‘e’, ‘X’, ‘Y’, ‘Z’, ‘o’]
使用切片语法时也可以指定步长(step 参数),但这个时候就要求所赋值的新元素的个数与原有元素的个数相同,例如:
1 | nums = [40, 36, 89, 2, 36, 100, 7] |
运行结果:
[40, 0.025, 89, -99, 36, 20.5, 7]
list列表查找元素
Python 列表(list)提供了 index() 和 count() 方法,它们都可以用来查找元素。
1.index()方法
index() 方法用来查找某个元素在列表中出现的位置(也就是索引),如果该元素不存在,则会导致 ValueError 错误,所以在查找之前最好使用 count() 方法判断一下。
index() 的语法格式为:
1 | listname.index(obj, start, end) |
其中,listname 表示列表名称,obj 表示要查找的元素,start 表示起始位置,end 表示结束位置。
start 和 end 参数用来指定检索范围:
- start 和 end 可以都不写,此时会检索整个列表;
- 如果只写 start 不写 end,那么表示检索从 start 到末尾的元素;
- 如果 start 和 end 都写,那么表示检索 start 和 end 之间的元素。
index() 方法会返回元素所在列表中的索引值。
index() 方法使用举例:
1 | nums = [40, 36, 89, 2, 36, 100, 7, -20.5, -999] |
运行结果:
1 | 3 |
2.count()方法
count() 方法用来统计某个元素在列表中出现的次数,基本语法格式为:
1 | listname.count(obj) |
其中,listname 代表列表名,obj 表示要统计的元素。
如果 count() 返回 0,就表示列表中不存在该元素,所以 count() 也可以用来判断列表中的某个元素是否存在。
count() 用法示例
1 | nums = [40, 36, 89, 2, 36, 100, 7, -20.5, 36] |
运行结果:
36出现了3次
列表中存在100这个元素
元组Tuple
元组(tuple)是 Python 中另一个重要的序列结构,和列表类似,元组也是由一系列按特定顺序排序的元素组成。
元组和列表(list)的不同之处在于:
- 列表的元素是可以更改的,包括修改元素值,删除和插入元素,所以列表是可变序列;
- 而元组一旦被创建,它的元素就不可更改了,所以元组是不可变序列。
元组也可以看做是不可变的列表,通常情况下,元组用于保存无需修改的内容。
从形式上看,元组的所有元素都放在一对小括号( )
中,相邻元素之间用逗号,
分隔,如下所示:
1 | (element1, element2, ... , elementn) |
其中 element1~elementn 表示元组中的各个元素,个数没有限制,只要是 Python 支持的数据类型就可以。
从存储内容上看,元组可以存储整数、实数、字符串、列表、元组等任何类型的数据,并且在同一个元组中,元素的类型可以不同,例如:
1 | ("https://os-guangchuang.gitee.io/note/", 1, [2,'a'], ("abc",3.0)) |
在这个元组中,有多种类型的数据,包括整形、字符串、列表、元组。
另外,我们都知道,列表的数据类型是 list,那么元组的数据类型是什么呢?我们不妨通过 type() 函数来查看一下:
1 | type( ("https://os-guangchuang.gitee.io/note/",1,[2,'a'],("abc",3.0)) ) |
可以看到,元组是 tuple 类型,这也是很多教程中用 tuple 指代元组的原因。
创建元组
1.使用小括号直接创建
通过( )
创建元组后,一般使用=
将它赋值给某个变量,具体格式为:
1 | tuplename = (element1, element2, ..., elementn) |
其中,tuplename 表示变量名,element1 ~ elementn 表示元组的元素。
例如,下面的元组都是合法的:
1 | num = (7, 14, 21, 28, 35) |
在 Python 中,元组通常都是使用一对小括号将所有元素包围起来的,但小括号不是必须的,只要将各元素用逗号隔开,Python 就会将其视为元组,请看下面的例子:
1 | course = "Python教程", "https://os-guangchuang.gitee.io/note/" |
运行结果为:
1 | ('Python教程', 'https://os-guangchuang.gitee.io/note/') |
需要注意的一点是,当创建的元组中只有一个字符串类型的元素时,该元素后面必须要加一个逗号,
,否Python 解释器会将它视为字符串。请看下面的代码:
1 | #最后加上逗号 |
运行结果:
1 | <class 'tuple'> |
你看,只有变量 a 才是元组,后面的变量 b 是一个字符串。
2.使用tuple()函数创建
除了使用( )
创建元组外,Python 还提供了一个内置的函数 tuple(),用来将其它数据类型转换为元组类型。
tuple() 的语法格式如下:
1 | tuple(data) |
其中,data 表示可以转化为元组的数据,包括字符串、元组、range 对象等。
tuple() 使用示例:
1 | #将字符串转换成元组 |
运行结果为:
1 | ('h', 'e', 'l', 'l', 'o') |
访问元组元素
和列表一样,我们可以使用索引(Index)访问元组中的某个元素(得到的是一个元素的值),也可以使用切片访问元组中的一组元素(得到的是一个新的子元组)。
使用索引访问元组元素的格式为:
1 | tuplename[i] |
其中,tuplename 表示元组名字,i 表示索引值。元组的索引可以是正数,也可以是负数。
使用切片访问元组元素的格式为:
1 | tuplename[start : end : step] |
其中,start 表示起始索引,end 表示结束索引,step 表示步长。
以上两种方式我们已在《Python序列》中进行了讲解,这里就不再赘述了,仅作示例演示,请看下面代码:
1 | url = tuple("https://os-guangchuang.gitee.io/note/") |
运行结果:
1 | p |
修改元组
前面我们已经说过,元组是不可变序列,元组中的元素不能被修改,所以我们只能创建一个新的元组去替代旧的元组。
例如,对元组变量进行重新赋值:
1 | tup = (100, 0.5, -36, 73) |
运行结果:
1 | (100, 0.5, -36, 73) |
另外,还可以通过连接多个元组(使用+
可以拼接元组)的方式向元组中添加新元素,例如:
1 | tup1 = (100, 0.5, -36, 73) |
运行结果:
1 | (100, 0.5, -36, 73, (3+12j), -54.6, 99) |
使用+
拼接元组以后,tup1 和 tup2 的内容没法发生改变,这说明生成的是一个新的元组。
删除元组
当创建的元组不再使用时,可以通过 del 关键字将其删除,例如:
1 | tup = ('Java教程',"https://os-guangchuang.gitee.io/note/") |
运行结果:
1 | ('Java教程', 'http://c.biancheng.net/java/') |
Python 自带垃圾回收功能,会自动销毁不用的元组,所以一般不需要通过 del 来手动删除。
字典Dict
Python 字典(dict)是一种无序的、可变的序列,它的元素以“键值对(key-value)”的形式存储。相对地,列表(list)和元组(tuple)都是有序的序列,它们的元素在底层是挨着存放的。
字典类型是 Python 中唯一的映射类型。“映射”是数学中的术语,简单理解,它指的是元素之间相互对应的关系,即通过一个元素,可以唯一找到另一个元素。如图 1 所示。
字典中,习惯将各元素对应的索引称为键(key),各个键对应的元素称为值(value),键及其关联的值称为“键值对”。
字典类型很像学生时代常用的新华字典。我们知道,通过新华字典中的音节表,可以快速找到想要查找的汉字。其中,字典里的音节表就相当于字典类型中的键,而键对应的汉字则相当于值。
总的来说,字典类型所具有的主要特征如表 1 所示。
和列表、元组一样,字典也有它自己的类型。Python 中,字典的数据类型为 dict,通过 type() 函数即可查看:
1 | 'one': 1, 'two': 2, 'three': 3} #a是一个字典类型 a = { |
创建字典
1.使用{}创建字典
由于字典中每个元素都包含两部分,分别是键(key)和值(value),因此在创建字典时,键和值之间使用冒号:
分隔,相邻元素之间使用逗号,
分隔,所有元素放在大括号{ }
中。
使用{ }
创建字典的语法格式如下:
1 | dictname = {'key':'value1', 'key2':'value2', ..., 'keyn':valuen} |
其中 dictname 表示字典变量名,keyn : valuen 表示各个元素的键值对。需要注意的是,同一字典中的各个键必须唯一,不能重复。
如下代码示范了使用花括号语法创建字典:
1 | #使用字符串作为key |
运行结果:
1 | {'数学': 95, '英语': 92, '语文': 84} |
可以看到,字典的键可以是整数、字符串或者元组,只要符合唯一和不可变的特性就行;字典的值可以是 Python 支持的任意数据类型。
2.使用fromkeys()方法创建字典
Python 中,还可以使用 dict 字典类型提供的 fromkeys() 方法创建带有默认值的字典,具体格式为:
1 | dictname = dict.fromkeys(list,value=None) |
其中,list 参数表示字典中所有键的列表(list);value 参数表示默认值,如果不写,则为空值 None。
请看下面的例子:
1 | knowledge = ['语文', '数学', '英语'] |
运行结果:
1 | {'语文': 60, '英语': 60, '数学': 60} |
可以看到,knowledge 列表中的元素全部作为了 scores 字典的键,而各个键对应的值都是 60。这种创建方式通常用于初始化字典,设置 value 的默认值。
3.通过dict()映射函数创建字典
通过 dict() 函数创建字典的写法有多种,表 2 罗列出了常用的几种方式,它们创建的都是同一个字典 a。
注意,无论采用以上哪种方式创建字典,字典中各元素的键都只能是字符串、元组或数字,不能是列表。列表是可变的,不能作为键。
如果不为 dict() 函数传入任何参数,则代表创建一个空的字典,例如:
1 | # 创建空的字典 |
运行结果为:
1 | {} |
访问字典
列表和元组是通过下标来访问元素的,而字典不同,它通过键来访问对应的值。因为字典中的元素是无序的,每个元素的位置都不固定,所以字典也不能像列表和元组那样,采用切片的方式一次性访问多个元素。
Python 访问字典元素的具体格式为:
1 | dictname[key] |
其中,dictname 表示字典变量的名字,key 表示键名。注意,键必须是存在的,否则会抛出异常。
请看下面的例子:
1 | tup = (['two',26], ['one',88], ['three',100], ['four',-59]) |
运行结果:
1 | 88 |
除了上面这种方式外,Python 更推荐使用 dict 类型提供的 get() 方法来获取指定键对应的值。当指定的键不存在时,get() 方法不会抛出异常。
get() 方法的语法格式为:
1 | dictname.get(key[,default]) |
其中,dictname 表示字典变量的名字;key 表示指定的键;default 用于指定要查询的键不存在时,此方法返回的默认值,如果不手动指定,会返回 None。
get() 使用示例:
1 | a = dict(two=0.65, one=88, three=100, four=-59) |
运行结果:
1 | 该键不存在 |
删除字典
和删除列表、元组一样,手动删除字典也可以使用 del 关键字,例如:
1 | a = dict(two=0.65, one=88, three=100, four=-59) |
运行结果:
1 | {'two': 0.65, 'one': 88, 'three': 100, 'four': -59} |
字典基本操作
1.添加键值对
为字典添加新的键值对很简单,直接给不存在的 key 赋值即可,具体语法格式如下:
1 | dictname[key] = value |
对各个部分的说明:
- dictname 表示字典名称。
- key 表示新的键。
- value 表示新的值,只要是 Python 支持的数据类型都可以。
下面代码演示了在现有字典基础上添加新元素的过程:
1 | a = {'数学':95} |
运行结果:
1 | {'数学': 95} |
2.修改键值对
Python 字典中键(key)的名字不能被修改,我们只能修改值(value)。
字典中各元素的键必须是唯一的,因此,如果新添加元素的键与已存在元素的键相同,那么键所对应的值就会被新的值替换掉,以此达到修改元素值的目的。请看下面的代码:
1 | a = {'数学': 95, '语文': 89, '英语': 90} |
运行结果:
1 | {'数学': 95, '语文': 89, '英语': 90} |
可以看到,字典中没有再添加一个{'语文':100}
键值对,而是对原有键值对{'语文': 89}
中的 value 做了修改。
3.删除键值对
如果要删除字典中的键值对,还是可以使用 del 语句。例如:
1 | # 使用del语句删除键值对 |
运行结果:
1 | {'英语': 90} |
4.判断是否存在指定键值对
如果要判断字典中是否存在指定键值对,首先应判断字典中是否有对应的键。判断字典是否包含指定键值对的键,可以使用 in 或 not in 运算符。
需要指出的是,对于 dict 而言,in 或 not in 运算符都是基于 key 来判断的。
例如如下代码:
1 | a = {'数学': 95, '语文': 89, '英语': 90} |
运行结果:
1 | True |
通过 in(或 not in)运算符,我们可以很轻易地判断出现有字典中是否包含某个键,如果存在,由于通过键可以很轻易的获取对应的值,因此很容易就能判断出字典中是否有指定的键值对。
字典其它操作
1.keys()、values()和items()方法
将这三个方法放在一起介绍,是因为它们都用来获取字典中的特定数据:
- keys() 方法用于返回字典中的所有键(key);
- values() 方法用于返回字典中所有键对应的值(value);
- items() 用于返回字典中所有的键值对(key-value)。
请看下面的例子:
1 | scores = {'数学': 95, '语文': 89, '英语': 90} |
运行结果:
1 | dict_keys(['数学', '语文', '英语']) |
可以发现,keys()、values() 和 items() 返回值的类型分别为 dict_keys、dict_values 和 dict_items。
在 Python 3.x 中如果想使用这三个方法返回的数据,一般有下面两种方案:
1.使用 list() 函数,将它们返回的数据转换成列表,例如:
1 | a = {'数学': 95, '语文': 89, '英语': 90} |
运行结果:
1 | ['数学', '语文', '英语'] |
2.使用 for in 循环遍历它们的返回值,例如:
1 | a = {'数学': 95, '语文': 89, '英语': 90} |
运行结果:
1 | 数学 语文 英语 |
2.copy()方法
copy() 方法返回一个字典的拷贝,也即返回一个具有相同键值对的新字典,例如:
1 | a = {'one': 1, 'two': 2, 'three': [1,2,3]} |
运行结果:
1 | {'one': 1, 'two': 2, 'three': [1, 2, 3]} |
可以看到,copy() 方法将字典 a 的数据全部拷贝给了字典 b。
注意,copy() 方法所遵循的拷贝原理,既有深拷贝,也有浅拷贝。拿拷贝字典 a 为例,copy() 方法只会对最表层的键值对进行深拷贝,也就是说,它会再申请一块内存用来存放 {‘one’: 1, ‘two’: 2, ‘three’: []};而对于某些列表类型的值来说,此方法对其做的是浅拷贝,也就是说,b 中的 [1,2,3] 的值不是自己独有,而是和 a 共有。
请看下面的例子:
1 | a = {'one': 1, 'two': 2, 'three': [1,2,3]} |
运行结果:
1 | {'one': 1, 'two': 2, 'three': [1, 2, 3], 'four': 100} |
3.update()方法
update() 方法可以使用一个字典所包含的键值对来更新己有的字典。
在执行 update() 方法时,如果被更新的字典中己包含对应的键值对,那么原 value 会被覆盖;如果被更新的字典中不包含对应的键值对,则该键值对被添加进去。
请看下面的代码:
1 | a = {'one': 1, 'two': 2, 'three': 3} |
运行结果:
1 | {'one': 4.5, 'two': 2, 'three': 3, 'four': 9.3} |
从运行结果可以看出,由于被更新的字典中已包含 key 为“one”的键值对,因此更新时该键值对的 value 将被改写;而被更新的字典中不包含 key 为“four”的键值对,所以更新时会为原字典增加一个新的键值对。
4.pop()和popitem()方法
pop() 和 popitem() 都用来删除字典中的键值对,不同的是,pop() 用来删除指定的键值对,而 popitem() 用来随机删除一个键值对,它们的语法格式如下:
1 | dictname.pop(key) |
其中,dictname 表示字典名称,key 表示键。
下面的代码演示了两个函数的用法:
1 | a = {'数学': 95, '语文': 89, '英语': 90, '化学': 83, '生物': 98, '物理': 89} |
运行结果:
1 | {'数学': 95, '语文': 89, '英语': 90, '化学': 83, '生物': 98, '物理': 89} |
其实,说 popitem() 随机删除字典中的一个键值对是不准确的,虽然字典是一种无须的列表,但键值对在底层也是有存储顺序的,popitem() 总是弹出底层中的最后一个 key-value,这和列表的 pop() 方法类似,都实现了数据结构中“出栈”的操作。
5.setdefault()方法
setdefault() 方法用来返回某个 key 对应的 value,其语法格式如下:
1 | dictname.setdefault(key, defaultvalue) |
说明,dictname 表示字典名称,key 表示键,defaultvalue 表示默认值(可以不写,不写的话是 None)。
当指定的 key 不存在时,setdefault() 会先为这个不存在的 key 设置一个默认的 defaultvalue,然后再返回 defaultvalue。
也就是说,setdefault() 方法总能返回指定 key 对应的 value:
- 如果该 key 存在,那么直接返回该 key 对应的 value;
- 如果该 key 不存在,那么先为该 key 设置默认的 defaultvalue,然后再返回该 key 对应的 defaultvalue。
请看下面的代码:
1 | a = {'数学': 95, '语文': 89, '英语': 90} |
运行结果:
1 | {'数学': 95, '语文': 89, '英语': 90} |
集合Set
Python 中的集合,和数学中的集合概念一样,用来保存不重复的元素,即集合中的元素都是唯一的,互不相同。
从形式上看,和字典类似,Python 集合会将所有元素放在一对大括号 {} 中,相邻元素之间用“,”分隔,如下所示:
1 | {element1,element2,...,elementn} |
其中,elementn 表示集合中的元素,个数没有限制。
从内容上看,同一集合中,只能存储不可变的数据类型,包括整形、浮点型、字符串、元组,无法存储列表、字典、集合这些可变的数据类型,否则 Python 解释器会抛出 TypeError 错误。比如说:
1 | 'a':1}} {{ |
并且需要注意的是,数据必须保证是唯一的,因为集合对于每种数据元素,只会保留一份。例如:
1 | 1,2,1,(1,2,3),'c','c'} { |
由于 Python 中的 set 集合是无序的,所以每次输出时元素的排序顺序可能都不相同。
创建set集合
1.使用{}创建
在 Python 中,创建 set 集合可以像列表、元素和字典一样,直接将集合赋值给变量,从而实现创建集合的目的,其语法格式如下:
1 | setname = {element1,element2,...,elementn} |
其中,setname 表示集合的名称,起名时既要符合 Python 命名规范,也要避免与 Python 内置函数重名。
如下例所示:
1 | a = {1,'c',1,(1,2,3),'c'} |
运行结果:
1 | {1, 'c', (1, 2, 3)} |
2.使用set()函数创建
set() 函数为 Python 的内置函数,其功能是将字符串、列表、元组、range 对象等可迭代对象转换成集合。该函数的语法格式如下:
1 | setname = set(iteration) |
其中,iteration 就表示字符串、列表、元组、range 对象等数据。
例如:
1 | set1 = set("c.biancheng.net") |
运行结果:
1 | set1: {'a', 'g', 'b', 'c', 'n', 'h', '.', 't', 'i', 'e'} |
注意,如果要创建空集合,只能使用 set() 函数实现。因为直接使用一对 {},Python 解释器会将其视为一个空字典。
访问set集合
由于集合中的元素是无序的,因此无法向列表那样使用下标访问元素。Python 中,访问集合元素最常用的方法是使用循环结构,将集合中的数据逐一读取出来。
例如:
1 | a = {1,'c',1,(1,2,3),'c'} |
运行结果:
1 | 1 c (1, 2, 3) |
由于目前尚未学习循环结构,以上代码初学者只需初步了解,后续学习循环结构后自然会明白。
删除set集合
和其他序列类型一样,手动函数集合类型,也可以使用 del() 语句,例如:
1 | a = {1,'c',1,(1,2,3),'c'} |
运行结果:
1 | {1, 'c', (1, 2, 3)} |
set集合基本操作
1.向set集合添加元素
set 集合中添加元素,可以使用 set 类型提供的 add() 方法实现,该方法的语法格式为:
1 | setname.add(element) |
其中,setname 表示要添加元素的集合,element 表示要添加的元素内容。
需要注意的是,使用 add() 方法添加的元素,只能是数字、字符串、元组或者布尔类型(True 和 False)值,不能添加列表、字典、集合这类可变的数据,否则 Python 解释器会报 TypeError 错误。例如:
1 | a = {1,2,3} |
运行结果:
1 | {(1, 2), 1, 2, 3} |
2.从set集合中删除元素
删除现有 set 集合中的指定元素,可以使用 remove() 方法,该方法的语法格式如下:
1 | setname.remove(element) |
使用此方法删除集合中元素,需要注意的是,如果被删除元素本就不包含在集合中,则此方法会抛出 KeyError 错误,例如:
1 | a = {1,2,3} |
运行结果:
1 | {2, 3} |
上面程序中,由于集合中的元素 1 已被删除,因此当再次尝试使用 remove() 方法删除时,会引发 KeyError 错误。
如果我们不想在删除失败时令解释器提示 KeyError 错误,还可以使用 discard() 方法,此方法和 remove() 方法的用法完全相同,唯一的区别就是,当删除集合中元素失败时,此方法不会抛出任何错误。
例如:
1 | a = {1,2,3} |
运行结果:
1 | {2, 3} |
3.set集合做交集、并集、差集运算
集合最常做的操作就是进行交集、并集、差集以及对称差集运算,首先有必要给大家普及一下各个运算的含义。
图 1 中,有 2 个集合,分别为 set1={1,2,3} 和 set2={3,4,5},它们既有相同的元素,也有不同的元素。以这两个集合为例,分别做不同运算的结果如表 1 所示。
set集合其它操作
前面学习了 set 集合,本节来一一学习 set 类型提供的方法。首先,通过 dir(set) 命令可以查看它有哪些方法:
1 | dir(set) |
各个方法的具体语法结构及功能如表 1 所示。
frozenset集合
set 集合是可变序列,程序可以改变序列中的元素;frozenset 集合是不可变序列,程序不能改变序列中的元素。set 集合中所有能改变集合本身的方法,比如 remove()、discard()、add() 等,frozenset 都不支持;set 集合中不改变集合本身的方法,fronzenset 都支持。
我们可以在交互式编程环境中输入dir(frozenset)来查看 frozenset 集合支持的方法:
1 | dir(frozenset) |
frozenset 集合的这些方法和 set 集合中同名方法的功能是一样的。
两种情况下可以使用 fronzenset:
- 当集合的元素不需要改变时,我们可以使用 fronzenset 替代 set,这样更加安全。
- 有时候程序要求必须是不可变对象,这个时候也要使用 fronzenset 替代 set。比如,字典(dict)的键(key)就要求是不可变对象。
下面程序演示了 frozenset 的用法:
1 | s = {'Python', 'C', 'C++'} |
运行结果:
1 | s = {'Python', frozenset({'Java', 'Shell'}), 'C', 'C++'} |
需要注意的是,set 集合本身的元素必须是不可变的, 所以 set 的元素不能是 set,只能是 frozenset。第 6 行代码向 set 中添加 frozenset 是没问题的,因为 frozenset 是不可变的;但是,第 10 行代码中尝试向 set 中添加子 set,这是不允许的,因为 set 是可变的。
课后作业
1.略