4. 列表、元组和字典

本章将会介绍 Python 内置的三种常用数据结构:列表(list)、元组(tuple)和字典(dict),这三种数据结构都可以用于保存多项数据,其中列表和元组较为相似,都可以按顺序保存元素,并可以通过索引访问元素,不同的是元组中的元素是不可修改的,而列表是可修改的。字典中存储的则是 key-value 类型的数据。

4.1. 列表和元组

列表和元组都可以顺序保存元素,并可以通过索引访问元素。两者较为相似,不同的是元组中的元素是不可变的,元组一旦被构建出来,程序就不能修改元组所包含的元素,而列表是可变的,程序可以修改列表中所包含的元素。

4.1.1. 创建列表和元组

创建列表和元组的语法也有点相似,区别只是创建列表使用方括号 [],创建元组使用圆括号 (),并在括号中列出元素,元素之间以英文逗号 , 隔开。

创建列表的语法格式如下:

[el, e2, e3, ...]

创建元组的语法格式如下:

(el, e2, e3, ...)

列表和元组的创建过程如下代码所示:

# 使用方括号定义列表
list_a = ["Hello world", 20, "Hello Python"]
print(list_a) # ['Hello world', 20, 'Hello Python']
print(type(list_a)) # <class 'list'>
# 使用圆括号定义元组
tuple_a = ("Hello world", 20, "Hello Python")
print(tuple_a) # ('Hello world', 20, 'Hello Python')
print(type(tuple_a)) # <class 'tuple'>

4.1.2. 通过索引使用元素

列表和元组中都包含了多个元素,并且元素也有各自的索引。程序可通过索引来访问这些元素,区别只是在元组中不能修改元素。在通过索引访问元素时,索引都是从 0 开始的,在 Python 中也支持负数索引,如倒数第 1 个元素的索引为 -1。其中的对应关系如下图所示:

输入图片说明

访问列表和元组中的元素的代码如下所示:

list_a = ["Hello world", 20, "Hello Python"]
print(list_a[0]) # Hello world
print(list_a[-1]) # Hello Python
tuple_a = ("Hello world", 20, "Hello Python")
print(tuple_a[0]) # Hello world
print(tuple_a[-1]) # Hello Python

4.1.2. 子序列

列表和元组也可使用索引获取其中的一段,这种用法被称为 slice (分片或切片)。slice 的完整语法格式如下:

[start:end:step]

其中,start、end 是两个索引值,可以使用正数或负数,其中负数表示从倒数开始。 slice 表示从 start 索引的元素开始,包含 start 索引的元素,到 end 索引的元素结束,不包含 end 索引的元素。step 表示步长。slice 的使用方法如下代码所示:

list_a = ["l1", "l2", "l3", "l4", "l5", "l6"]
# slice
list_b = list_a[1:4]
print(list_b) # ['l2', 'l3', 'l4']
list_c = list_a[1:-1]
print(list_c) # ['l2', 'l3', 'l4', 'l5']

4.1.3. 加法

列表和元组支持加法运算,加法的和就是两个列表或元组所包含的元素的总和。元组和列表的加法运算如下代码所示:

list_a = ["la1", "la2", "la3"]
list_b = ["lb1", "lb2", "lb3"]
list_c = list_a + list_b
print(list_c) # ['la1', 'la2', 'la3', 'lb1', 'lb2', 'lb3']

tuple_a = ("ta1", "ta2", "ta3")
tuple_b = ("tb1", "tb2", "tb3")
tuple_c = tuple_a + tuple_b
print(tuple_c) # ('ta1', 'ta2', 'ta3', 'tb1', 'tb2', 'tb3')

列表只能和列表相加,元组只能和元组相加。

4.1.4. 乘法

列表和元组可以和整数执行乘法运算,列表和元组乘法的意义就是把它们包含的元素重复 N 次,其中 N 就是被乘的倍数,使用方法如下代码所示:

list_a = ["la1", "la2", "la3"]
list_b = list_a * 3 # 重复 3 遍
print(list_b) # ['la1', 'la2', 'la3', 'la1', 'la2', 'la3', 'la1', 'la2', 'la3']

tuple_a = ("ta1", "ta2", "ta3")
tuple_b = tuple_a * 2 # 重复 2 遍
print(tuple_b) # ('ta1', 'ta2', 'ta3', 'ta1', 'ta2', 'ta3')

4.1.5. in 运算符

in 运算符用于判断某个元素是否在列表或元组内,与 in 运算符相反的是 not in 运算符,表示的是某个元素是否不在列表或元组内,例如如下代码:

tuple_test = ("hello", "hello world", 1, 2)
print("hello" in tuple_test) # True
print(5 in tuple_test) # False
print("helloworld" not in tuple_test) # True

4.1.6. 长度、最大值和最小值

Python 提供了内置的 len()max()min() 全局函数来获取元组或列表的长度、最大值和最小值。由于 max()min() 要对元组、列表中的元素比较大小,因此程序要求传给 max()min() 函数的元组、列表的元素必须是相同类型且可以比较大小。使用方法如下代码所示:

list_a = ["la1", "la2", "la3"]
print(len(list_a)) # 3
print(max(list_a)) # la3
print(min(list_a)) # la1

4.1.7. 序列打包和序列解包

Python 还提供了序列打包( Packing )和序列解包( Unpacking )的功能。 简单来说,Python 允许 支持以下两种赋值方式:

  • 把多个值赋给一个变量时,Python 会自动将多个值封装成元组,即打包
  • Python 允许将元组或列表直接赋值给多个变量,此时序列的各元素会被依次赋值给每个变量,即解包

使用方法如下代码所示:

a = 1, 2, 3
# 打包
print(type(a)) # <class 'tuple'>
print(a) # (1, 2, 3)
# 解包
v1,v2,v3 = a
print(v1) # 1
print(v2) # 2
print(v3) # 3

4.2. 列表的特殊方法

列表与元组最大的区别在于:元组是不可改变的,列表是可改变的。元组支持的操作,列表基本上都支持,除此之外,列表还具有一些特殊的方法。

4.2.1. 创建列表

除了使用方括号 [] 语法创建列表之外,Python 还提供了一个内置的 list() 函数来创建列表,list() 函数可用于将元组 、区间( range )等对象转换为列表。使用方法如下代码所示:

tuple_a = (0,1,2,3,4,5,6,7,8,9)
# 将元组转换成列表
list_a = list(tuple_a)
print(list_a) # [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
# 使用 range() 函数创建区间对象
range_b = range(10)
print(range_b) # range(0, 10)
# 将区间转换成列表
list_b = list(range_b)
print(list_b) # [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
# 创建区间时还指定了步长,指定步长为2
list_c = list(range(0, 10, 2))
print(list_c) # [0, 2, 4, 6, 8]

4.2.2. 增加列表元素

为列表增加元素可调用列表的 append() 方法,该方法会把传入的参数追加到列表的末尾。append() 方法既可接收单个值,也可接收元组、列表等,但该方法只是把元组、列表当成单个
元素,这样就会形成在列表中嵌套列表、嵌套元组的情形。使用方法如下代码所示:

list_a = list(range(5))
print(list_a) # [0, 1, 2, 3, 4]
# 增加元素 5
list_a.append(5)
print(list_a) # [0, 1, 2, 3, 4, 5]
# 增加 列表
list_b = list(range(6,10))
print(list_b)
list_a.append(list_b)
print(list_a) # [0, 1, 2, 3, 4, 5, [6, 7, 8, 9]]

4.2.3. 删除列表元素

删除列表元素可以使用 del 语句。使用 del 语句既可删除列表中的单个元素,也可直接删除列表的中间一段。使用方法如下代码所示:

list_a = list(range(10))
print(list_a) # [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
# 删除第 3 个元素
del list_a[2]
print(list_a) # [0, 1, 3, 4, 5, 6, 7, 8, 9]
# 删除第 2 个到第 4 个元素
del list_a[1:3] # 删除第 2 个和第 3 个元素
print(list_a) # [0, 4, 5, 6, 7, 8, 9]

list_b = list(range(10))
# 删除第 3 个到倒数第 2 个元素,间隔为 2
del list_b[2:-2:2]
print(list_b) # [0, 1, 3, 5, 7, 8, 9]

使用 del 语句不仅可以删除列表元素,也可以删除普通变量,使用方法如下代码所示:

name = 'felixzhao'
print(name) # felixzhao
# 删除 name 变量
del name
print(name) # NameError

当通过 del 语句删除了 name 变量后,再访问 name 变量时将会引发 NameError 错误。除使用 del 语句之外,Python 还提供了 remove() 方法来删除列表元素,该方法并不是根据索引来删除元素的,而是根据元素本身来执行删除操作的。该方法只删除第一个找到的元素,如果找不到该元素,该方法将会引发 ValueError 错误,使用方法如下代码所示:

list_a = list(range(5)) * 2
print(list_a) # [0, 1, 2, 3, 4, 0, 1, 2, 3, 4]
# 删除第一次找到的 1
list_a.remove(1)
print(list_a) # [0, 2, 3, 4, 0, 1, 2, 3, 4]
# 删除不存在的元素
list_a.remove(5) # ValueError

列表还提供了一个 clear() 方法,该方法用于清空列表中的所有元素,使用方法如下代码所示:

list_a = list(range(5)) * 2
print(list_a) # [0, 1, 2, 3, 4, 0, 1, 2, 3, 4]
# 清空列表
list_a.clear()
print(list_a) # []

4.2.4. 修改列表元素

列表的元素相当于变量,因此程序可以对列表的元素赋值,这样即可修改列表的元素,使用方法如下代码所示:

list_a = list(range(5))
print(list_a) # [0, 1, 2, 3, 4]
# 修改第 3 个元素
list_a[2] = 5
print(list_a) # [0, 1, 5, 3, 4]

4.2.5. 列表的其他常用方法

除上面介绍的增加元素、删除元素、修改元素方法之外,列表还包含了一些其他的常用方法,主要有count()index()pop()reverse()sort()等方法。

count() 方法用于统计列表中某个元素出现的次数,使用方法如下代码所示:

list_a = list(range(3)) * 4
print(list_a) # [0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2]
# 统计 0 出现的次数
print(list_a.count(0)) # 4

index() 方法用于判断某个元素在列表中出现的位置,如果该元素没有出现,则会引发 ValueError 错误。在使用 index() 方法时还可传入 start、end 参数,用于在列表的指定范围内搜索元素,使用方法如下代码所示:

list_a = list(range(3)) * 4
print(list_a) # [0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2]
# 判断 2 在列表中出现的位置
print(list_a.index(2)) # 2
# 判断 2 在列表指定范围中出现的位置
print(list_a.index(2, 3, 6)) # 5
# 索引不存在的元素
print(list_a.index(5)) # ValueError

pop() 方法用于将列表当成栈使用,实现元素出栈。 栈是一种特殊的数据结构,它可以实现先进后出功能,即先加入的元素,反而后出栈。对于列表来说,入栈使用的是 append() 方法,出栈使用的是 pop() 方法,使用方法如下代码所示:

list_a = []
# 入栈
list_a.append(0)
list_a.append(1)
list_a.append(2)
print(list_a) # [0, 1, 2]
# 出栈
list_a.pop()
print(list_a) # [0, 1]

reverse() 方法用于将列表中的元素反向存放,使用方法如下代码所示:

list_a = list(range(1, 8))
# 将 list_a 列表元素反转
list_a.reverse()
print(list_a) # [7, 6, 5, 4, 3, 2, 1]

sort() 方法用于对列表中元素进行排序,使用方法如下代码所示:

import random

# 随机生成 10 个 [1,100] 之间的随机整数
list_a = list(random.randint(1, 100) for i in range(10))
print(list_a) # [88, 26, 78, 56, 51, 66, 31, 92, 80, 2]
list_a.sort()
print(list_a) # [2, 26, 31, 51, 56, 66, 78, 80, 88, 92]

由上述代码可以看出,sort() 方法默认是按照从小到大排序的,除支持默认排序之外,还可传入 key 和 reverse 两个参数,而且这两个参数必须通过参数名指定。key 参数用于为每个元素都生成一个比较大小的“键”,reverse 参数则用于执行是否需要反转排序,如果将该参数设为 Tru e,将会改为从大到小排序,使用方法如下代码所示:

list_a = ['Ruby', 'Go', 'Swift', 'Kotlin', 'Erlang', 'Python']
print(list_a) # ['Ruby', 'Go', 'Swift', 'Kotlin', 'Erlang', 'Python']
# 默认的排序,字典序
list_a.sort()
print(list_a) # ['Erlang', 'Go', 'Kotlin', 'Python', 'Ruby', 'Swift']
# 指定 key 的排序
list_a.sort(key=len)
print(list_a) # ['Go', 'Ruby', 'Swift', 'Erlang', 'Kotlin', 'Python']
# 再指定反向排序
list_a.sort(key=len, reverse=True)
print(list_a) # ['Erlang', 'Kotlin', 'Python', 'Swift', 'Ruby', 'Go']

4.3. 字典

字典 dict 也是 Python 提供的一种常用的数据结构,用于存放 key-value 关系的数据。

4.3.1. 字典数据结构

字典用于存储具有 key-value 这种映射关系的数据,这种数据中包含了两组数据,其中一组数据被称为“键”,即 key,另一组数据被称为“值”,即 value。两者之间存在着对应关系,通过 key 可以访问到对应的 value。一个典型的例子如下所示:

{  
"name":"felixzhao",  
"gender":"male",  
"age":33  
}

表示的是一个人的信息,包括人名(name),性别(gender)和年龄(age)。

4.3.2. 创建字典

在 Python 中有两种方法创建字典,分别为:

  • 使用花括号 {} 创建字典
  • 使用 dict() 函数创建字典。

在使用花括号 {} 语法创建字典时,花括号中应包含多个 key-value 对,key 与 value 之间用英文冒号隔开,多个 key-value 对之间用英文逗号隔开。字典创建的如下代码所示:

dict_a = {"name":"felixzhao", "gender":"male", "age":33}
print(dict_a["name"]) # felixzhao

在字典中,除了字符串可以作为 key,元组也可以作为其 key。还可以使用 dict() 函数创建字典,如下代码所示:

# 创建空的字典
dict_a = dict()
print(dict_a) # {}
dict_b = dict(name="felixzhao", gender="male", age=33)
print(dict_b) # {'name': 'felixzhao', 'gender': 'male', 'age': 33}

4.3.3. 字典的基本用法

在字典中,对字典的操作都是基于 key 的。基本操作如下所示:

  • 访问 value
  • 添加 key-value 对
  • 删除 key-value 对
  • 修改 key-value 对
  • 判断指定 key-value 对是否存在

通过 key 访问 value 使用的是方括号 [] 语法,并在方括号中放入 key,使用方法如下代码所示:

dict_a = dict(name="felixzhao", gender="male", age=33)
# 输出 name
print(dict_a["name"]) # felixzhao

如果要为字典添加 key-value 对,只需为不存在的 key 赋值即可,使用方法如下代码所示:

dict_a = dict(name="felixzhao", gender="male", age=33)
# 新增 birthday
dict_a["birthday"] = '0102'
print(dict_a) # {'name': 'felixzhao', 'gender': 'male', 'age': 33, 'birthday': '0102'}

如果要删除宇典中的 key-value 对,可以使用 del 语句,使用方法如下代码所示:

dict_a = dict(name="felixzhao", gender="male", age=33, birthday='0102')
# 删除 birthday
del dict_a["birthday"]
print(dict_a) # {'name': 'felixzhao', 'gender': 'male', 'age': 33}

del 是语句,不是函数

如果对字典中存在的 key-value 对赋值,新的 value 就会覆盖原有的 value,这样就可改变字典中的 key-value 对,使用方法如下代码所示:

dict_a = dict(name="felixzhao", gender="male", age=33)
# 修改 age 的值
dict_a["age"] = 34
print(dict_a) # {'name': 'felixzhao', 'gender': 'male', 'age': 34}

如果要判断字典是否包含指定的 key,则可以使用 innot in 运 算符。对于字典而言,innot in 运算符都是基于 key 来判断的,使用方法如下代码所示:

dict_a = dict(name="felixzhao", gender="male", age=33)
# 判断 age 是否在 dict 中
print("age" in dict_a) # True
# 判断 birthdady 是否不在 dict 中
print("birthday" not in dict_a) # True

4.3.4. 字典中其他的常用方法

clear() 方法用于清空字典中所有的 key-value 对,使用方法如下代码所示:

dict_a = dict(name="felixzhao", gender="male", age=33)
# 清空 dict
dict_a.clear()
print(dict_a) # {}

get() 方法是根据 key 来获取对应的 value,与方括号 [] 语法不同的是,get() 方法相当于方括号 [] 语法的增强版,当使用方括号 [] 语法访问并不存在的 key 时,字典会引发 KeyError 错 误,但如果使用 get() 方法访问不存在的 key,则会简单地返回 None ,不会导致错误,使用方法如下代码所示:

dict_a = dict(name="felixzhao", gender="male", age=33)
# 访问存在的 key : name
print(dict_a.get("name")) # felixzhao
print(dict_a["name"]) # felixzhao
# 访问不存在的 key : birthday
print(dict_a.get("birthday")) # None
print(dict_a["birthday"]) # KeyError

update() 方法可使用一个字典所包含的 key-value 对来更新已有的字典。在执行 update() 方法 时,如果被更新的字典中已包含对应的 key-value 对,那么原 value 会被覆盖,如果被更新的字典中不包含对应的 key-value 对,则该 key-value 对会被添加进字典中,使用方法如下代码所示:

dict_a = dict(name="felixzhao", gender="male", age=33)
print(dict_a) # {'name': 'felixzhao', 'gender': 'male', 'age': 33}
# 更新 age
dict_a.update({"age":34})
print(dict_a) # {'name': 'felixzhao', 'gender': 'male', 'age': 34}
# 更新不存在的字段
dict_a.update({"birthday":"0102"})
print(dict_a) # {'name': 'felixzhao', 'gender': 'male', 'age': 34, 'birthday': '0102'}

items()keys()values() 分别用于获取字典中的所有 key-value 对、所有 key、所有 value。这三个方法依次返回 dict_itemsdict_keysdict_values 对象,可以通过 list() 方法将其转换成列表,使用方法如下代码所示:

dict_a = dict(name="felixzhao", gender="male", age=33)
print(dict_a) # {'name': 'felixzhao', 'gender': 'male', 'age': 33}
# items
dic_items = dict_a.items()
print(type(dic_items)) # <class 'dict_items'>
print(list(dic_items)) # [('name', 'felixzhao'), ('gender', 'male'), ('age', 33)]
# keys
dic_keys = dict_a.keys()
print(type(dic_keys)) # <class 'dict_keys'>
print(list(dic_keys)) # ['name', 'gender', 'age']
# values
dic_values = dict_a.values()
print(type(dic_values)) # <class 'dict_values'>
print(list(dic_values)) # ['felixzhao', 'male', 33]

pop() 方法用于获取指定 key 对应的 value,并删除这个 key-value 对,使用方法如下代码所示:

dict_a = dict(name="felixzhao", gender="male", age=33)
print(dict_a) # {'name': 'felixzhao', 'gender': 'male', 'age': 33}
# pop() 方法
age = dict_a.pop("age")
print(age) # 33
print(dict_a) # {'name': 'felixzhao', 'gender': 'male'}

4.4. 本章小结

本章主要介绍了 Python 内置的三种重要的数据结构: 列表、元组和字典,这三种数据结构是 Python 编程语言的基础,其中列表,元组都代表元素有序、可通过索引访问元素的数据结构,区别只是列表是可变的,程序可以添加、删除、替换列表元素。而元组是不可变的,程序不能改变元组中的元素。而字典则用于保存 key-value 对。

本章需要掌握知识点:

  1. 列表和元组的基本使用方法,两者之间的区别
  2. 列表区别于元组的特有的方法
  3. 字典的基本使用方法