Python 基础篇(五):第五章:数据类型

第五章. 数据容器:管理多个数据

在前面的章节中,我们学会了用变量存储单个数据,用运算符处理数据。但在实际开发中,我们经常需要处理大量数据。比如,一个班级 50 个学生的成绩、一个公司 100 个员工的信息、一个网站 1000 个用户的订单。

如果用单个变量存储这些数据,代码会变得非常冗长且难以维护。这一章,我们将学习 Python 的数据容器,它们可以帮助我们高效地管理多个数据。


5.1. 从单个变量到数据容器

5.1.1. 一个真实的困境:如何存储班级成绩?

假设你是一名老师,需要记录班级 5 个学生的考试成绩。你可能会这样写:

1
2
3
4
5
score_1 = 90
score_2 = 85
score_3 = 92
score_4 = 88
score_5 = 95

看起来还可以接受。但现在,校长要求你计算这 5 个学生的平均分。你需要这样写:

1
2
average = (score_1 + score_2 + score_3 + score_4 + score_5) / 5
print(f"平均分:{average}")

如果班级有 50 个学生呢?你需要定义 50 个变量,然后在计算平均分时把它们全部加起来。这显然不现实。

更糟糕的是,如果学期中途转来一个新学生,你需要:

  1. 定义一个新变量 score_51
  2. 修改计算平均分的代码,把 score_51 加进去
  3. 修改除数从 50 改为 51

这种做法有三个致命问题:

  1. 代码冗长:50 个变量,50 行代码
  2. 难以维护:每次增减学生,都要修改多处代码
  3. 无法批量操作:想找出最高分、最低分,需要写大量比较代码

列表可以解决这个问题

1
scores = [90, 85, 92, 88, 95]

一个变量,存储所有成绩。计算平均分也变得简单:

1
2
average = sum(scores) / len(scores)
print(f"平均分:{average}")

新增学生?只需要在列表末尾添加一个数字:

1
scores.append(87)  # 新学生的成绩

这就是数据容器的价值:用一个变量管理多个数据


5.1.2. Python 的四种数据容器对比

Python 提供了四种常用的数据容器,它们各有特点:

容器类型特点适用场景示例
列表 list有序、可变、可重复存储一组可修改的数据[90, 85, 92]
元组 tuple有序、不可变、可重复存储不应被修改的数据(90, 85, 92)
字典 dict无序、可变、键唯一存储键值对数据{"name": "张三", "age": 25}
集合 set无序、可变、不可重复去重、集合运算{1, 2, 3}

有序 vs 无序

  • 有序:元素有固定的位置,可以通过索引访问(如 scores[0]
  • 无序:元素没有固定位置,不能通过索引访问

可变 vs 不可变

  • 可变:创建后可以修改、添加、删除元素
  • 不可变:创建后不能修改,只能重新创建

可重复 vs 不可重复

  • 可重复:允许存储相同的元素(如 [1, 1, 2]
  • 不可重复:自动去重(如 {1, 1, 2} 会变成 {1, 2}

5.1.3. 如何选择合适的容器?

场景 1:存储一组学生成绩

需求:可以修改成绩、添加新成绩、删除错误成绩。

选择:列表(可变、有序)

1
scores = [90, 85, 92, 88, 95]

场景 2:存储一个人的基本信息

需求:姓名、年龄、城市等信息,需要通过名称快速访问。

选择:字典(键值对)

1
2
person = {"name": "张三", "age": 25, "city": "北京"}
print(person["name"]) # 通过键访问值

场景 3:存储地理坐标

需求:经度和纬度,创建后不应被修改。

选择:元组(不可变)

1
location = (39.9042, 116.4074)  # 北京的经纬度

场景 4:统计班级中有多少个不同的姓氏

需求:自动去重。

选择:集合(不可重复)

1
2
surnames = {"张", "李", "王", "张", "李"}
print(surnames) # 输出:{'张', '李', '王'}(自动去重)

5.2. 列表(list):可变的有序容器

5.2.1. 为什么需要列表?

在 5.1.1 中,我们已经看到了列表的价值。现在,让我们深入理解列表的本质。

列表是什么?

列表是一个有序的容器,可以存储多个元素。这些元素可以是不同类型的数据:

1
2
3
4
5
# 存储相同类型的数据
scores = [90, 85, 92, 88, 95]

# 存储不同类型的数据
person = ["张三", 25, True, 175.5]

列表的特点

  1. 有序:元素有固定的位置,第一个元素永远是第一个
  2. 可变:可以修改、添加、删除元素
  3. 可重复:允许存储相同的元素

5.2.2. 列表的创建与访问

创建列表

1
2
3
4
5
6
7
8
9
# 方式 1:使用方括号
scores = [90, 85, 92, 88, 95]

# 方式 2:使用 list() 函数
scores = list([90, 85, 92, 88, 95])

# 方式 3:创建空列表
empty_list = []
also_empty = list()

访问列表元素

列表的索引从 0 开始,第一个元素的索引是 0,第二个是 1,以此类推。

1
2
3
4
5
scores = [90, 85, 92, 88, 95]

print(scores[0]) # 90(第一个元素)
print(scores[1]) # 85(第二个元素)
print(scores[4]) # 95(第五个元素)

负数索引

Python 支持负数索引,从列表末尾开始计数。-1 表示最后一个元素,-2 表示倒数第二个,以此类推。

1
2
3
4
5
scores = [90, 85, 92, 88, 95]

print(scores[-1]) # 95(最后一个元素)
print(scores[-2]) # 88(倒数第二个元素)
print(scores[-5]) # 90(倒数第五个元素,也就是第一个)

为什么索引从 0 开始?

这不仅仅是习惯,背后有技术原因。索引实际上表示的是"偏移量"(offset)。第一个元素距离列表起始位置的偏移是 0,第二个元素偏移 1 个位置,以此类推。这种设计让内存地址计算更高效。

虽然一开始可能不习惯,但理解了这个原理后,你会发现这是一个很自然的设计。


5.2.3. 列表的索引与切片

切片:获取列表的一部分

切片可以一次性获取列表的多个元素。语法是 list[start:end:step]

  • start:起始索引(包含)
  • end:结束索引(不包含)
  • step:步长(可选,默认为 1)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
scores = [90, 85, 92, 88, 95, 78, 82]

# 获取前 3 个元素
print(scores[0:3]) # [90, 85, 92]

# 省略起始索引,默认从 0 开始
print(scores[:3]) # [90, 85, 92]

# 获取第 3 个到最后一个元素
print(scores[2:]) # [92, 88, 95, 78, 82]

# 获取第 2 个到第 5 个元素
print(scores[1:5]) # [85, 92, 88, 95]

# 使用步长,每隔一个元素取一个
print(scores[::2]) # [90, 92, 95, 82]

# 逆序获取所有元素
print(scores[::-1]) # [82, 78, 95, 88, 92, 85, 90]

切片的关键规则

  • 结束索引不包含在结果中(scores[0:3] 只包含索引 0、1、2)
  • 如果起始索引大于等于结束索引,返回空列表
  • 切片不会修改原列表,而是返回一个新列表

常见困惑:为什么结束索引不包含?

这是 Python 的设计哲学。这样设计有两个好处:

  1. scores[:3]scores[3:] 可以完美分割列表,没有重叠
  2. scores[0:3] 的长度就是 3 - 0 = 3,计算更直观

5.2.4. 添加元素的三种方式

方式 1:append() - 在末尾添加一个元素

1
2
3
scores = [90, 85, 92]
scores.append(88)
print(scores) # [90, 85, 92, 88]

append() 是最常用的添加方法,它会把元素添加到列表的末尾。

方式 2:insert() - 在指定位置插入元素

1
2
3
scores = [90, 85, 92]
scores.insert(1, 88) # 在索引 1 的位置插入 88
print(scores) # [90, 88, 85, 92]

insert() 需要两个参数:插入位置的索引和要插入的元素。原来在这个位置及之后的元素会向后移动。

方式 3:extend() - 批量添加元素

1
2
3
scores = [90, 85, 92]
scores.extend([88, 95, 78])
print(scores) # [90, 85, 92, 88, 95, 78]

extend() 会把另一个列表的所有元素逐一添加到当前列表的末尾。

append() vs extend():新手最容易混淆的点

1
2
3
4
5
6
7
8
9
# append() 会把整个列表作为一个元素添加
scores = [90, 85, 92]
scores.append([88, 95])
print(scores) # [90, 85, 92, [88, 95]](嵌套列表)

# extend() 会把列表的元素逐一添加
scores = [90, 85, 92]
scores.extend([88, 95])
print(scores) # [90, 85, 92, 88, 95](展开添加)

如何记住?

  • append 的意思是"追加",把整个东西追加到末尾
  • extend 的意思是"扩展",把列表扩展开来

5.2.5. 删除元素的四种方式

方式 1:remove() - 删除指定的元素

1
2
3
scores = [90, 85, 92, 88, 85]
scores.remove(85)
print(scores) # [90, 92, 88, 85](只删除第一个 85)

remove() 会删除列表中第一个匹配的元素。如果元素不存在,会报错。

1
2
scores = [90, 85, 92]
scores.remove(100) # ValueError: list.remove(x): x not in list

方式 2:pop() - 删除指定索引的元素

1
2
3
4
scores = [90, 85, 92, 88, 95]
deleted = scores.pop(2) # 删除索引 2 的元素
print(scores) # [90, 85, 88, 95]
print(deleted) # 92(返回被删除的元素)

pop() 会删除指定索引的元素,并返回这个元素。如果不指定索引,默认删除最后一个元素。

1
2
3
4
scores = [90, 85, 92, 88, 95]
last = scores.pop() # 删除最后一个元素
print(scores) # [90, 85, 92, 88]
print(last) # 95

方式 3:clear() - 清空列表

1
2
3
scores = [90, 85, 92, 88, 95]
scores.clear()
print(scores) # []

clear() 会删除列表中的所有元素,但列表本身还在。

方式 4:del - 删除元素或切片

1
2
3
4
5
6
7
8
9
10
11
12
13
14
scores = [90, 85, 92, 88, 95]

# 删除单个元素
del scores[2]
print(scores) # [90, 85, 88, 95]

# 删除切片
scores = [90, 85, 92, 88, 95]
del scores[1:3]
print(scores) # [90, 88, 95]

# 删除整个列表
del scores
# print(scores) # NameError: name 'scores' is not defined

del 是 Python 的关键字,不是列表的方法。它可以删除任何变量。

四种删除方式的对比

方式删除依据返回值适用场景
remove(x)元素的值知道要删除的值
pop(i)元素的索引被删除的元素知道要删除的位置,且需要这个值
clear()全部删除清空列表
del索引或切片删除多个元素或整个列表

5.2.6. 修改元素与查找元素

修改元素

直接通过索引赋值即可修改元素:

1
2
3
scores = [90, 85, 92, 88, 95]
scores[1] = 87 # 修改索引 1 的元素
print(scores) # [90, 87, 92, 88, 95]

也可以通过切片修改多个元素:

1
2
3
scores = [90, 85, 92, 88, 95]
scores[1:3] = [87, 93] # 修改索引 1 和 2 的元素
print(scores) # [90, 87, 93, 88, 95]

查找元素:index() 方法

index() 方法返回元素第一次出现的索引:

1
2
3
scores = [90, 85, 92, 88, 85]
position = scores.index(85)
print(position) # 1(第一个 85 的索引)

如果元素不存在,会报错:

1
2
scores = [90, 85, 92, 88, 95]
position = scores.index(100) # ValueError: 100 is not in list

查找元素:in 运算符

in 运算符可以判断元素是否存在于列表中,返回 TrueFalse

1
2
3
4
scores = [90, 85, 92, 88, 95]

print(92 in scores) # True
print(100 in scores) # False

统计元素出现次数:count() 方法

1
2
3
scores = [90, 85, 92, 88, 85, 85]
count = scores.count(85)
print(count) # 3

获取列表长度:len() 函数

1
2
3
scores = [90, 85, 92, 88, 95]
length = len(scores)
print(length) # 5

5.2.7. 列表的排序:sort vs sorted

sort() - 原地排序

sort() 方法会直接修改原列表,按升序排列:

1
2
3
scores = [90, 85, 92, 88, 95]
scores.sort()
print(scores) # [85, 88, 90, 92, 95]

降序排列需要设置 reverse=True

1
2
3
scores = [90, 85, 92, 88, 95]
scores.sort(reverse=True)
print(scores) # [95, 92, 90, 88, 85]

sorted() - 返回新列表

sorted() 函数不会修改原列表,而是返回一个新的排序后的列表:

1
2
3
4
5
scores = [90, 85, 92, 88, 95]
sorted_scores = sorted(scores)

print(scores) # [90, 85, 92, 88, 95](原列表不变)
print(sorted_scores) # [85, 88, 90, 92, 95](新列表)

同样可以降序排列:

1
2
sorted_scores = sorted(scores, reverse=True)
print(sorted_scores) # [95, 92, 90, 88, 85]

sort() vs sorted():何时用哪个?

特性sort()sorted()
是否修改原列表
返回值None新列表
适用场景不需要保留原列表需要保留原列表

常见错误:误以为 sort() 有返回值

1
2
3
4
scores = [90, 85, 92, 88, 95]
sorted_scores = scores.sort()
print(sorted_scores) # None(sort() 没有返回值)
print(scores) # [85, 88, 90, 92, 95](原列表已排序)

如何避免? 记住:sort() 是"就地排序",它修改原列表,不返回新列表。


5.2.8. 列表的常见错误与避坑指南

错误 1:索引越界

1
2
scores = [90, 85, 92]
print(scores[3]) # IndexError: list index out of range

为什么会犯这个错误? 因为我们习惯性地认为"长度为 3"意味着"可以访问到第 3 个"。但由于索引从 0 开始,长度为 3 的列表有效索引是 0、1、2。

如何避免? 记住这个规则:最大索引 = 列表长度 - 1


错误 2:混淆 append 和 extend

1
2
3
scores = [90, 85, 92]
scores.append([88, 95])
print(scores) # [90, 85, 92, [88, 95]](嵌套列表,不是我们想要的)

如何避免?

  • 添加单个元素用 append()
  • 添加多个元素用 extend()

错误 3:切片的结束索引不包含

1
2
scores = [90, 85, 92, 88, 95]
print(scores[1:3]) # [85, 92](不包含索引 3)

为什么这样设计? 这样可以让 scores[:3]scores[3:] 完美分割列表,没有重叠。


错误 4:误以为 sort() 有返回值

1
2
3
scores = [90, 85, 92]
sorted_scores = scores.sort()
print(sorted_scores) # None

如何避免?

  • 需要修改原列表用 sort()
  • 需要新列表用 sorted()

5.2.9. 实战:成绩管理器(不用循环的版本)

现在,我们用学到的知识做一个简单的成绩管理器。

需求

  • 存储 5 个学生的成绩
  • 添加新成绩
  • 删除错误成绩
  • 修改成绩
  • 查找最高分和最低分
  • 计算平均分
  • 排序成绩
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
# 初始化成绩列表
scores = [90, 85, 92, 88, 95]
print(f"初始成绩:{scores}")

# 添加新成绩
scores.append(87)
print(f"添加新成绩后:{scores}")

# 删除错误成绩(假设 85 是错误的)
scores.remove(85)
print(f"删除错误成绩后:{scores}")

# 修改成绩(假设第一个成绩应该是 91)
scores[0] = 91
print(f"修改成绩后:{scores}")

# 查找最高分和最低分
highest = max(scores)
lowest = min(scores)
print(f"最高分:{highest}")
print(f"最低分:{lowest}")

# 计算平均分
average = sum(scores) / len(scores)
print(f"平均分:{average:.2f}")

# 排序成绩(降序)
sorted_scores = sorted(scores, reverse=True)
print(f"排序后的成绩:{sorted_scores}")

# 统计某个分数出现的次数
count_92 = scores.count(92)
print(f"92 分出现了 {count_92} 次")

# 查找某个分数的位置
if 92 in scores:
position = scores.index(92)
print(f"92 分在索引 {position} 的位置")

输出结果

1
2
3
4
5
6
7
8
9
10
初始成绩:[90, 85, 92, 88, 95]
添加新成绩后:[90, 85, 92, 88, 95, 87]
删除错误成绩后:[90, 92, 88, 95, 87]
修改成绩后:[91, 92, 88, 95, 87]
最高分:95
最低分:87
平均分:90.60
排序后的成绩:[95, 92, 91, 88, 87]
92 分出现了 1 次
92 分在索引 1 的位置

5.3. 元组(tuple):不可变的列表

5.3.1. 元组 vs 列表:何时用元组?

在学习元组之前,你可能会有一个疑问:既然列表已经很好用了,为什么还需要元组?

元组的核心特点:不可变

元组和列表最大的区别是:元组创建后不能修改。你不能添加、删除、修改元组中的元素。

1
2
3
4
5
6
7
# 列表:可以修改
scores_list = [90, 85, 92]
scores_list[0] = 95 # 正确

# 元组:不能修改
scores_tuple = (90, 85, 92)
# scores_tuple[0] = 95 # TypeError: 'tuple' object does not support item assignment

为什么需要不可变的容器?

在某些场景下,我们希望数据创建后不被修改。比如:

场景 1:地理坐标

地理坐标(经度、纬度)一旦确定,就不应该被修改。如果用列表存储,可能会被意外修改:

1
2
3
4
5
6
7
# 用列表存储(不推荐)
beijing = [39.9042, 116.4074]
beijing[0] = 40.0 # 意外修改了纬度

# 用元组存储(推荐)
beijing = (39.9042, 116.4074)
# beijing[0] = 40.0 # TypeError(防止意外修改)

场景 2:函数返回多个值

当函数需要返回多个值时,通常使用元组:

1
2
3
4
5
6
7
8
9
def get_user_info():
name = "张三"
age = 25
city = "北京"
return name, age, city # 实际上返回的是元组 ("张三", 25, "北京")

# 接收返回值
user_name, user_age, user_city = get_user_info()
print(user_name, user_age, user_city) # 张三 25 北京

场景 3:作为字典的键

字典的键必须是不可变的。列表不能作为字典的键,但元组可以:

1
2
3
4
5
6
7
8
9
10
# 用元组作为字典的键
locations = {
(39.9042, 116.4074): "北京",
(31.2304, 121.4737): "上海"
}

print(locations[(39.9042, 116.4074)]) # 北京

# 列表不能作为字典的键
# locations[[39.9042, 116.4074]] = "北京" # TypeError: unhashable type: 'list'

元组 vs 列表的选择原则

  • 数据需要修改 → 用列表
  • 数据不应被修改 → 用元组
  • 不确定 → 用列表(更灵活)

5.3.2. 元组的创建:单元素陷阱

创建元组

1
2
3
4
5
6
7
8
9
10
11
12
# 方式 1:使用小括号
scores = (90, 85, 92)

# 方式 2:省略小括号
scores = 90, 85, 92

# 方式 3:使用 tuple() 函数
scores = tuple([90, 85, 92])

# 方式 4:创建空元组
empty_tuple = ()
also_empty = tuple()

单元素元组的陷阱

这是新手最容易犯的错误:

1
2
3
4
5
6
7
8
9
10
11
# ❌ 错误:这不是元组,是整数
t = (42)
print(type(t)) # <class 'int'>

# ✅ 正确:单元素元组必须加逗号
t = (42,)
print(type(t)) # <class 'tuple'>

# 也可以省略括号
t = 42,
print(type(t)) # <class 'tuple'>

为什么单元素元组必须加逗号?

因为小括号在 Python 中有多种用途:

  • 数学运算:(1 + 2) * 3
  • 函数调用:print(42)
  • 元组:(1, 2, 3)

如果单元素元组不加逗号,Python 无法区分它是元组还是数学运算。加上逗号后,Python 就知道这是一个元组。


5.3.3. 元组的访问与切片

元组的访问和切片与列表完全相同:


1
2
3
4
5
6
7
8
9
10
11
scores = (90, 85, 92, 88, 95)

# 索引访问
print(scores[0]) # 90
print(scores[-1]) # 95

# 切片
print(scores[1:4]) # (85, 92, 88)
print(scores[:3]) # (90, 85, 92)
print(scores[::2]) # (90, 92, 95)
print(scores[::-1]) # (95, 88, 92, 85, 90)(逆序)

元组的方法

由于元组不可变,它只有两个方法:

1
2
3
4
5
6
7
scores = (90, 85, 92, 88, 85)

# count():统计元素出现次数
print(scores.count(85)) # 2

# index():查找元素的索引
print(scores.index(92)) # 2

元组也支持常用的内置函数

1
2
3
4
5
6
7
scores = (90, 85, 92, 88, 95)

print(len(scores)) # 5(长度)
print(max(scores)) # 95(最大值)
print(min(scores)) # 85(最小值)
print(sum(scores)) # 450(总和)
print(sorted(scores)) # [85, 88, 90, 92, 95](返回列表,不是元组)

5.3.4. 元组解包:优雅的多重赋值

元组解包是 Python 的一个优雅特性,它可以让你一次性给多个变量赋值。

基础解包

1
2
3
4
5
6
7
8
9
# 创建元组
person = ("张三", 25, "北京")

# 解包赋值
name, age, city = person

print(name) # 张三
print(age) # 25
print(city) # 北京

实际上,我们在第三章学过的多重赋值,本质上就是元组解包:

1
2
3
# 这两种写法是等价的
a, b, c = 1, 2, 3
a, b, c = (1, 2, 3)

交换变量的值

元组解包让交换变量变得非常简单:

1
2
3
4
5
6
a, b = 10, 20
print(f"交换前:a={a}, b={b}")

# 交换变量
a, b = b, a
print(f"交换后:a={a}, b={b}")

在其他编程语言中,交换变量通常需要一个临时变量:

1
2
3
4
5
# 传统方法(不推荐)
a, b = 10, 20
temp = a
a = b
b = temp

Python 的元组解包让这个过程变得优雅而直观。

忽略不需要的值

有时候,我们只需要元组中的部分值,可以用下划线 _ 表示忽略:

1
2
3
4
5
6
7
8
9
person = ("张三", 25, "北京", "男")

# 只需要姓名和年龄
name, age, _, _ = person
print(name, age) # 张三 25

# 或者只忽略中间的值
name, _, city, _ = person
print(name, city) # 张三 北京

下划线 _ 是 Python 的惯例,表示"这个变量我不关心"。


5.3.5. 元组的不可变性:真的不能改吗?

元组本身不可变

元组创建后,不能添加、删除、修改元素:

1
2
3
4
5
6
7
8
9
10
scores = (90, 85, 92)

# ❌ 不能修改元素
# scores[0] = 95 # TypeError

# ❌ 不能添加元素
# scores.append(88) # AttributeError: 'tuple' object has no attribute 'append'

# ❌ 不能删除元素
# del scores[0] # TypeError

但可以创建新元组

虽然不能修改元组,但可以通过连接、重复等操作创建新元组:

1
2
3
4
5
6
7
8
9
10
11
12
scores = (90, 85, 92)

# 连接两个元组
new_scores = scores + (88, 95)
print(new_scores) # (90, 85, 92, 88, 95)

# 重复元组
repeated = scores * 2
print(repeated) # (90, 85, 92, 90, 85, 92)

# 原元组不变
print(scores) # (90, 85, 92)

元组中的可变对象可以修改

这是一个容易混淆的点。元组的不可变性指的是元组的结构不可变(元素的引用不能改变),但如果元组中包含可变对象(如列表),这些对象的内容是可以修改的:

1
2
3
4
5
6
7
8
9
# 元组中包含列表
data = (1, 2, [3, 4])

# ❌ 不能修改元组的结构
# data[2] = [5, 6] # TypeError

# ✅ 但可以修改列表的内容
data[2].append(5)
print(data) # (1, 2, [3, 4, 5])

如何理解?

想象元组是一个相框,里面有三个格子,每个格子放一张照片。元组的不可变性是指:

  • 不能增加或减少格子
  • 不能把某个格子的照片换成另一张

但如果某个格子里放的是一个相册(列表),你可以在相册里添加或删除照片,因为相册本身是可变的。


5.3.6. 元组的常见错误与避坑指南

错误 1:单元素元组忘记加逗号

1
2
3
4
5
6
7
# ❌ 错误
t = (42)
print(type(t)) # <class 'int'>(不是元组)

# ✅ 正确
t = (42,)
print(type(t)) # <class 'tuple'>

错误 2:尝试修改元组

1
2
scores = (90, 85, 92)
# scores[0] = 95 # TypeError: 'tuple' object does not support item assignment

如何避免? 如果需要修改数据,一开始就用列表,不要用元组。


错误 3:混淆元组和列表的语法

1
2
3
4
5
6
7
8
# 列表用方括号
scores_list = [90, 85, 92]

# 元组用小括号
scores_tuple = (90, 85, 92)

# ❌ 错误:用错了括号
# scores_tuple = [90, 85, 92] # 这是列表,不是元组

5.4. 字典(dict):键值对的世界

5.4.1. 为什么需要字典?

假设你要存储一个学生的信息:姓名、年龄、城市、成绩。用列表可以这样写:

1
student = ["张三", 25, "北京", 90]

但这样有一个问题:你需要记住每个位置代表什么。student[0] 是姓名,student[1] 是年龄,student[2] 是城市……如果信息很多,很容易搞混。

字典可以解决这个问题

1
2
3
4
5
6
7
8
9
student = {
"name": "张三",
"age": 25,
"city": "北京",
"score": 90
}

print(student["name"]) # 张三
print(student["age"]) # 25

字典使用"键值对"的方式存储数据。每个数据都有一个名字(键),通过名字可以快速找到对应的值。

字典的特点

  1. 无序:元素没有固定的位置(Python 3.7+ 保持插入顺序,但不应依赖这个特性)
  2. 可变:可以添加、删除、修改键值对
  3. 键唯一:每个键只能出现一次,重复的键会被覆盖

5.4.2. 字典的创建与访问

创建字典

1
2
3
4
5
6
7
8
9
# 方式 1:使用花括号
student = {"name": "张三", "age": 25, "city": "北京"}

# 方式 2:使用 dict() 函数
student = dict(name="张三", age=25, city="北京")

# 方式 3:创建空字典
empty_dict = {}
also_empty = dict()

访问字典的值

1
2
3
4
5
student = {"name": "张三", "age": 25, "city": "北京"}

# 通过键访问值
print(student["name"]) # 张三
print(student["age"]) # 25

如果键不存在会报错

1
2
student = {"name": "张三", "age": 25}
# print(student["city"]) # KeyError: 'city'

5.4.3. 字典的增删改查

添加或修改键值对

1
2
3
4
5
6
7
8
9
student = {"name": "张三", "age": 25}

# 添加新键值对
student["city"] = "北京"
print(student) # {'name': '张三', 'age': 25, 'city': '北京'}

# 修改已有键值对
student["age"] = 26
print(student) # {'name': '张三', 'age': 26, 'city': '北京'}

字典的赋值操作很智能:如果键不存在,就添加;如果键已存在,就修改。

删除键值对

1
2
3
4
5
6
7
8
9
10
11
12
13
14
student = {"name": "张三", "age": 25, "city": "北京"}

# 方式 1:del 关键字
del student["city"]
print(student) # {'name': '张三', 'age': 25}

# 方式 2:pop() 方法(返回被删除的值)
age = student.pop("age")
print(age) # 25
print(student) # {'name': '张三'}

# 方式 3:clear() 清空字典
student.clear()
print(student) # {}

查询键是否存在

1
2
3
4
5
student = {"name": "张三", "age": 25, "city": "北京"}

# 使用 in 运算符
print("name" in student) # True
print("score" in student) # False

5.4.4. get() vs 直接访问:避免 KeyError

当访问不存在的键时,直接访问会报错:

1
2
student = {"name": "张三", "age": 25}
# print(student["city"]) # KeyError: 'city'

get() 方法可以避免这个问题

1
2
3
4
5
6
7
8
9
student = {"name": "张三", "age": 25}

# 如果键不存在,返回 None
city = student.get("city")
print(city) # None

# 可以指定默认值
city = student.get("city", "未知")
print(city) # 未知

get() vs 直接访问的对比

方式键存在键不存在适用场景
dict[key]返回值报错 KeyError确定键存在
dict.get(key)返回值返回 None不确定键是否存在
dict.get(key, default)返回值返回默认值需要默认值

字典的其他常用方法

1
2
3
4
5
6
7
8
9
10
11
12
13
student = {"name": "张三", "age": 25, "city": "北京"}

# keys():获取所有键
print(student.keys()) # dict_keys(['name', 'age', 'city'])

# values():获取所有值
print(student.values()) # dict_values(['张三', 25, '北京'])

# items():获取所有键值对
print(student.items()) # dict_items([('name', '张三'), ('age', 25), ('city', '北京')])

# len():获取键值对数量
print(len(student)) # 3

5.4.5. 字典的常见错误与避坑指南

错误 1:访问不存在的键

1
2
student = {"name": "张三", "age": 25}
# print(student["city"]) # KeyError: 'city'

如何避免? 使用 get() 方法或先用 in 判断键是否存在。


错误 2:键必须是不可变类型

1
2
3
4
5
6
# ❌ 错误:列表不能作为键
# data = {[1, 2]: "value"} # TypeError: unhashable type: 'list'

# ✅ 正确:元组可以作为键
data = {(1, 2): "value"}
print(data[(1, 2)]) # value

为什么? 字典的键必须是不可变的(可哈希的)。列表是可变的,不能作为键。


错误 3:重复的键会被覆盖

1
2
student = {"name": "张三", "age": 25, "age": 26}
print(student) # {'name': '张三', 'age': 26}(第二个 age 覆盖了第一个)

5.4.6. 实战:通讯录管理器

现在,我们用字典做一个简单的通讯录管理器。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
# 创建通讯录(字典的字典)
contacts = {
"张三": {"phone": "13800138000", "email": "zhangsan@example.com", "city": "北京"},
"李四": {"phone": "13900139000", "email": "lisi@example.com", "city": "上海"},
"王五": {"phone": "13700137000", "email": "wangwu@example.com", "city": "广州"}
}

print("=" * 50)
print("通讯录管理器")
print("=" * 50)

# 查询联系人
name = "张三"
if name in contacts:
info = contacts[name]
print(f"\n{name} 的信息:")
print(f" 电话:{info['phone']}")
print(f" 邮箱:{info['email']}")
print(f" 城市:{info['city']}")
else:
print(f"\n未找到 {name} 的信息")

# 添加新联系人
contacts["赵六"] = {
"phone": "13600136000",
"email": "zhaoliu@example.com",
"city": "深圳"
}
print(f"\n已添加 赵六 的信息")

# 修改联系人信息
contacts["张三"]["phone"] = "13800138001"
print(f"\n已更新 张三 的电话")

# 删除联系人
del contacts["李四"]
print(f"\n已删除 李四 的信息")

# 显示所有联系人
print(f"\n当前通讯录中有 {len(contacts)} 个联系人:")
for name in contacts.keys():
print(f" - {name}")

# 统计城市分布
cities = {}
for person_info in contacts.values():
city = person_info["city"]
if city in cities:
cities[city] += 1
else:
cities[city] = 1

print(f"\n城市分布:")
for city, count in cities.items():
print(f" {city}{count} 人")

输出结果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
==================================================
通讯录管理器
==================================================

张三 的信息:
电话:13800138000
邮箱:zhangsan@example.com
城市:北京

已添加 赵六 的信息

已更新 张三 的电话

已删除 李四 的信息

当前通讯录中有 3 个联系人:
- 张三
- 王五
- 赵六

城市分布:
北京:1 人
广州:1 人
深圳:1 人

5.5. 集合(set):去重与集合运算

5.5.1. 为什么需要集合?

假设你要统计一个班级中有多少个不同的姓氏。用列表存储所有学生的姓氏:

1
surnames = ["张", "李", "王", "张", "李", "赵", "张", "王"]

如果用列表,你需要手动去重。但集合可以自动去重:

1
2
3
surnames_set = {"张", "李", "王", "张", "李", "赵", "张", "王"}
print(surnames_set) # {'张', '李', '王', '赵'}(自动去重)
print(len(surnames_set)) # 4(不同姓氏的数量)

集合的特点

  1. 无序:元素没有固定的位置,不能通过索引访问
  2. 可变:可以添加、删除元素
  3. 不可重复:自动去重,相同的元素只保留一个

5.5.2. 集合的创建与特性

创建集合

1
2
3
4
5
6
7
8
9
10
11
12
# 方式 1:使用花括号
numbers = {1, 2, 3, 4, 5}

# 方式 2:使用 set() 函数
numbers = set([1, 2, 3, 4, 5])

# 方式 3:从列表创建(自动去重)
numbers = set([1, 2, 3, 3, 2, 1])
print(numbers) # {1, 2, 3}

# 方式 4:创建空集合(注意:不能用 {},那是空字典)
empty_set = set()

集合的自动去重

1
2
3
4
5
6
7
8
9
# 列表中有重复元素
scores = [90, 85, 92, 90, 88, 85]

# 转换为集合,自动去重
unique_scores = set(scores)
print(unique_scores) # {85, 88, 90, 92}

# 统计不同分数的数量
print(len(unique_scores)) # 4

集合是无序的

1
2
numbers = {5, 2, 8, 1, 9}
print(numbers) # 输出顺序可能是 {1, 2, 5, 8, 9},也可能是其他顺序

由于集合是无序的,不能通过索引访问元素:

1
2
numbers = {1, 2, 3}
# print(numbers[0]) # TypeError: 'set' object is not subscriptable

5.5.3. 集合的增删操作

添加元素

1
2
3
4
5
6
7
8
9
10
11
12
13
numbers = {1, 2, 3}

# add():添加单个元素
numbers.add(4)
print(numbers) # {1, 2, 3, 4}

# 添加已存在的元素,不会报错,但也不会重复添加
numbers.add(2)
print(numbers) # {1, 2, 3, 4}(2 没有重复)

# update():批量添加元素
numbers.update([5, 6, 7])
print(numbers) # {1, 2, 3, 4, 5, 6, 7}

删除元素

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
numbers = {1, 2, 3, 4, 5}

# remove():删除指定元素(元素不存在会报错)
numbers.remove(3)
print(numbers) # {1, 2, 4, 5}

# discard():删除指定元素(元素不存在不会报错)
numbers.discard(10) # 不会报错
print(numbers) # {1, 2, 4, 5}

# pop():随机删除一个元素并返回
removed = numbers.pop()
print(f"删除了:{removed}")
print(numbers)

# clear():清空集合
numbers.clear()
print(numbers) # set()

5.5.4. 集合运算:交并差补

集合支持数学中的集合运算,这在数据分析中非常有用。

交集:两个集合的共同元素

1
2
3
4
5
6
7
8
9
10
set1 = {1, 2, 3, 4, 5}
set2 = {4, 5, 6, 7, 8}

# 方式 1:使用 & 运算符
intersection = set1 & set2
print(intersection) # {4, 5}

# 方式 2:使用 intersection() 方法
intersection = set1.intersection(set2)
print(intersection) # {4, 5}

并集:两个集合的所有元素(去重)

1
2
3
4
5
6
7
8
9
10
set1 = {1, 2, 3, 4, 5}
set2 = {4, 5, 6, 7, 8}

# 方式 1:使用 | 运算符
union = set1 | set2
print(union) # {1, 2, 3, 4, 5, 6, 7, 8}

# 方式 2:使用 union() 方法
union = set1.union(set2)
print(union) # {1, 2, 3, 4, 5, 6, 7, 8}

差集:属于 set1 但不属于 set2 的元素

1
2
3
4
5
6
7
8
9
10
set1 = {1, 2, 3, 4, 5}
set2 = {4, 5, 6, 7, 8}

# 方式 1:使用 - 运算符
difference = set1 - set2
print(difference) # {1, 2, 3}

# 方式 2:使用 difference() 方法
difference = set1.difference(set2)
print(difference) # {1, 2, 3}

对称差集:不同时属于两个集合的元素

1
2
3
4
5
6
7
8
9
10
set1 = {1, 2, 3, 4, 5}
set2 = {4, 5, 6, 7, 8}

# 方式 1:使用 ^ 运算符
sym_diff = set1 ^ set2
print(sym_diff) # {1, 2, 3, 6, 7, 8}

# 方式 2:使用 symmetric_difference() 方法
sym_diff = set1.symmetric_difference(set2)
print(sym_diff) # {1, 2, 3, 6, 7, 8}

5.5.5. 集合的常见错误与避坑指南

错误 1:创建空集合用 {}

1
2
3
4
5
6
7
# ❌ 错误:这是空字典,不是空集合
empty = {}
print(type(empty)) # <class 'dict'>

# ✅ 正确:创建空集合
empty = set()
print(type(empty)) # <class 'set'>

错误 2:尝试通过索引访问集合

1
2
numbers = {1, 2, 3}
# print(numbers[0]) # TypeError: 'set' object is not subscriptable

如何避免? 记住:集合是无序的,不支持索引访问。


错误 3:集合中的元素必须是不可变类型

1
2
3
4
5
6
# ❌ 错误:列表不能作为集合的元素
# numbers = {[1, 2], [3, 4]} # TypeError: unhashable type: 'list'

# ✅ 正确:元组可以作为集合的元素
numbers = {(1, 2), (3, 4)}
print(numbers) # {(1, 2), (3, 4)}

5.5.6. 实战:数据去重与关系分析

场景 1:去除列表中的重复元素

1
2
3
4
5
6
7
8
# 原始数据(有重复)
scores = [90, 85, 92, 90, 88, 85, 95, 92]

# 去重
unique_scores = list(set(scores))
print(f"原始数据:{scores}")
print(f"去重后:{unique_scores}")
print(f"去重前有 {len(scores)} 个元素,去重后有 {len(unique_scores)} 个元素")

场景 2:分析两个班级的学生关系

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# 班级 A 的学生
class_a = {"张三", "李四", "王五", "赵六", "钱七"}

# 班级 B 的学生
class_b = {"王五", "赵六", "孙八", "周九", "吴十"}

# 同时在两个班级的学生(交集)
both_classes = class_a & class_b
print(f"同时在两个班级的学生:{both_classes}")

# 所有学生(并集)
all_students = class_a | class_b
print(f"所有学生:{all_students}")
print(f"总共有 {len(all_students)} 个学生")

# 只在班级 A 的学生(差集)
only_a = class_a - class_b
print(f"只在班级 A 的学生:{only_a}")

# 只在班级 B 的学生(差集)
only_b = class_b - class_a
print(f"只在班级 B 的学生:{only_b}")

# 只在一个班级的学生(对称差集)
only_one_class = class_a ^ class_b
print(f"只在一个班级的学生:{only_one_class}")

输出结果

1
2
3
4
5
6
同时在两个班级的学生:{'王五', '赵六'}
所有学生:{'张三', '李四', '王五', '赵六', '钱七', '孙八', '周九', '吴十'}
总共有 8 个学生
只在班级 A 的学生:{'张三', '李四', '钱七'}
只在班级 B 的学生:{'孙八', '周九', '吴十'}
只在一个班级的学生:{'张三', '李四', '钱七', '孙八', '周九', '吴十'}

5.6. 字符串的进阶操作

5.6.1. 字符串也是容器

在第三章中,我们学习了字符串的基础用法。现在,我们要深入理解:字符串也是一种容器

字符串是一个有序的、不可变的字符序列。你可以把它看作一个"只读的字符列表"。

1
2
3
4
5
6
7
8
9
10
11
12
text = "Python"

# 字符串有长度
print(len(text)) # 6

# 字符串可以通过索引访问
print(text[0]) # P
print(text[-1]) # n

# 字符串可以切片
print(text[0:3]) # Pyt
print(text[::2]) # Pto

5.6.2. 字符串的切片与索引

字符串的索引和切片与列表完全相同:

1
2
3
4
5
6
7
8
9
10
11
12
text = "Hello, Python!"

# 索引访问
print(text[0]) # H
print(text[7]) # P
print(text[-1]) # !

# 切片
print(text[0:5]) # Hello
print(text[7:13]) # Python
print(text[::2]) # Hlo yhn
print(text[::-1]) # !nohtyP ,olleH(逆序)

字符串是不可变的

虽然可以访问字符串的字符,但不能修改:

1
2
text = "Hello"
# text[0] = "h" # TypeError: 'str' object does not support item assignment

如果需要修改,只能创建新字符串:

1
2
3
text = "Hello"
new_text = "h" + text[1:]
print(new_text) # hello

5.6.3. 字符串的常用方法(分类讲解)

字符串有很多方法,我们按功能分类讲解。

判断类方法(返回 True/False)

1
2
3
4
5
6
7
8
9
10
11
text = "Hello123"

# 判断是否以指定内容开头/结尾
print(text.startswith("Hello")) # True
print(text.endswith("123")) # True

# 判断字符类型
print("123".isdigit()) # True(全为数字)
print("abc".isalpha()) # True(全为字母)
print("abc123".isalnum()) # True(全为字母或数字)
print(" ".isspace()) # True(全为空白字符)

查找类方法

1
2
3
4
5
6
7
8
9
text = "Hello, Python! Python is great!"

# find():查找子串位置(找不到返回 -1)
print(text.find("Python")) # 7(第一次出现的位置)
print(text.find("Java")) # -1(找不到)

# count():统计子串出现次数
print(text.count("Python")) # 2
print(text.count("o")) # 3

转换类方法

1
2
3
4
5
6
7
8
9
10
text = "Hello, Python!"

# 大小写转换
print(text.upper()) # HELLO, PYTHON!
print(text.lower()) # hello, python!
print(text.title()) # Hello, Python!(每个单词首字母大写)

# 替换
print(text.replace("Python", "Java")) # Hello, Java!
print(text.replace("l", "L")) # HeLLo, Python!

去除空格类方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
text = "   Hello, Python!   "

# 去除两端空格
print(text.strip()) # "Hello, Python!"

# 去除左侧空格
print(text.lstrip()) # "Hello, Python! "

# 去除右侧空格
print(text.rstrip()) # " Hello, Python!"

# 去除指定字符
text2 = "xxxHelloxxx"
print(text2.strip("x")) # "Hello"

5.6.4. 字符串的分割与拼接

split():分割字符串为列表

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 按空格分割
text = "Hello Python Java C++"
words = text.split()
print(words) # ['Hello', 'Python', 'Java', 'C++']

# 按指定分隔符分割
text = "2026-02-07"
parts = text.split("-")
print(parts) # ['2026', '02', '07']

# 限制分割次数
text = "a,b,c,d,e"
parts = text.split(",", 2) # 只分割 2 次
print(parts) # ['a', 'b', 'c,d,e']

join():拼接列表为字符串

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 用空格拼接
words = ["Hello", "Python", "Java"]
text = " ".join(words)
print(text) # "Hello Python Java"

# 用逗号拼接
text = ",".join(words)
print(text) # "Hello,Python,Java"

# 用换行符拼接
text = "\n".join(words)
print(text)
# 输出:
# Hello
# Python
# Java

split() 和 join() 的配合使用

1
2
3
4
5
# 场景:将日期格式从 "2026-02-07" 转换为 "2026/02/07"
date = "2026-02-07"
parts = date.split("-") # ['2026', '02', '07']
new_date = "/".join(parts) # "2026/02/07"
print(new_date)

5.6.5. 字符串的常见错误与避坑指南

错误 1:尝试修改字符串

1
2
text = "Hello"
# text[0] = "h" # TypeError: 'str' object does not support item assignment

如何避免? 记住:字符串是不可变的。如果需要修改,创建新字符串。


错误 2:混淆 split() 和 join() 的使用对象

1
2
3
4
5
6
7
8
9
10
11
12
13
# ❌ 错误:split() 是字符串的方法
# words = ["Hello", "Python"]
# text = words.split() # AttributeError: 'list' object has no attribute 'split'

# ✅ 正确:split() 用于字符串
text = "Hello Python"
words = text.split()

# ❌ 错误:join() 的参数是列表,但调用者是字符串
# text = ["Hello", "Python"].join(" ") # TypeError

# ✅ 正确:join() 用于字符串,参数是列表
text = " ".join(["Hello", "Python"])

如何记住?

  • split():字符串 → 列表("分割"字符串)
  • join():列表 → 字符串("拼接"列表)

错误 3:strip() 只去除两端的字符

1
2
text = "  Hello  Python  "
print(text.strip()) # "Hello Python"(中间的空格不会去除)

如果要去除所有空格,需要用 replace()

1
2
text = "  Hello  Python  "
print(text.replace(" ", "")) # "HelloPython"

5.7. 数据容器的类型转换

5.7.1. 列表、元组、集合的相互转换

列表 → 元组

1
2
3
4
scores_list = [90, 85, 92, 88, 95]
scores_tuple = tuple(scores_list)
print(scores_tuple) # (90, 85, 92, 88, 95)
print(type(scores_tuple)) # <class 'tuple'>

元组 → 列表

1
2
3
4
scores_tuple = (90, 85, 92, 88, 95)
scores_list = list(scores_tuple)
print(scores_list) # [90, 85, 92, 88, 95]
print(type(scores_list)) # <class 'list'>

列表 → 集合(自动去重)

1
2
3
scores_list = [90, 85, 92, 90, 88, 85]
scores_set = set(scores_list)
print(scores_set) # {85, 88, 90, 92}(自动去重)

集合 → 列表

1
2
3
scores_set = {90, 85, 92, 88, 95}
scores_list = list(scores_set)
print(scores_list) # [85, 88, 90, 92, 95](顺序可能不同)

元组 → 集合

1
2
3
scores_tuple = (90, 85, 92, 90, 88)
scores_set = set(scores_tuple)
print(scores_set) # {85, 88, 90, 92}(自动去重)

集合 → 元组

1
2
3
scores_set = {90, 85, 92, 88, 95}
scores_tuple = tuple(scores_set)
print(scores_tuple) # (85, 88, 90, 92, 95)(顺序可能不同)

5.7.2. 字符串与列表的转换

字符串 → 列表(split)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 按空格分割
text = "Hello Python Java"
words = text.split()
print(words) # ['Hello', 'Python', 'Java']

# 按指定分隔符分割
text = "apple,banana,cherry"
fruits = text.split(",")
print(fruits) # ['apple', 'banana', 'cherry']

# 将字符串拆分为字符列表
text = "Python"
chars = list(text)
print(chars) # ['P', 'y', 't', 'h', 'o', 'n']

列表 → 字符串(join)

1
2
3
4
5
6
7
8
9
10
11
words = ["Hello", "Python", "Java"]
text = " ".join(words)
print(text) # "Hello Python Java"

fruits = ["apple", "banana", "cherry"]
text = ",".join(fruits)
print(text) # "apple,banana,cherry"

chars = ['P', 'y', 't', 'h', 'o', 'n']
text = "".join(chars)
print(text) # "Python"

5.7.3. 类型转换的常见陷阱

陷阱 1:字典转换为列表

1
2
3
4
5
6
7
8
9
student = {"name": "张三", "age": 25, "city": "北京"}

# 转换为列表(只保留键)
keys = list(student)
print(keys) # ['name', 'age', 'city']

# 如果要保留键值对,需要用 items()
items = list(student.items())
print(items) # [('name', '张三'), ('age', 25), ('city', '北京')]

陷阱 2:集合转换后顺序不确定

1
2
3
numbers = [5, 2, 8, 1, 9, 2, 5]
unique = list(set(numbers))
print(unique) # 顺序可能是 [1, 2, 5, 8, 9],也可能是其他顺序

如果需要保持顺序,可以先排序:

1
2
3
numbers = [5, 2, 8, 1, 9, 2, 5]
unique = sorted(set(numbers))
print(unique) # [1, 2, 5, 8, 9](升序)

陷阱 3:join() 只能拼接字符串列表

1
2
3
4
5
6
numbers = [1, 2, 3, 4, 5]
# text = ",".join(numbers) # TypeError: sequence item 0: expected str instance, int found

# 需要先转换为字符串
text = ",".join(str(n) for n in numbers)
print(text) # "1,2,3,4,5"

注意:这里用到了生成器表达式 str(n) for n in numbers,它会在下一章详细讲解。现在你只需要知道,它可以把列表中的每个元素转换为字符串。


5.8. 本章小结

本章学习了 Python 的四种数据容器:列表、元组、字典、集合,以及字符串的进阶操作。

核心要点

容器类型特点使用场景关键操作
列表 list有序、可变、可重复存储可修改的数据append(), pop(), sort()
元组 tuple有序、不可变、可重复存储不应修改的数据元组解包、作为字典的键
字典 dict无序、可变、键唯一存储键值对数据get(), keys(), items()
集合 set无序、可变、不可重复去重、集合运算&, `

容器选择原则

  • 需要按顺序存储多个值 → 列表
  • 数据不应被修改 → 元组
  • 需要通过名称访问数据 → 字典
  • 需要去重或集合运算 → 集合

常见操作对比

操作列表元组字典集合
创建[1, 2, 3](1, 2, 3){"a": 1}{1, 2, 3}
访问list[0]tuple[0]dict["key"]不支持索引
修改
添加append()dict[key] = valueadd()
删除remove(), pop()del, pop()remove(), discard()
长度len()len()len()len()

下一章,我们将学习条件判断(if/elif/else)和用户输入(input),让程序能够根据不同情况做出不同反应。