考点 6. Python 的组合数据类型
掌握列表、元组、字典、集合等组合数据类型的基本操作。
Python 的组合数据类型(也叫容器类型)是指能一次性存储多个数据元素的类型,这些元素可以是相同/不同类型(如数字、字符串,甚至其他组合类型),核心作用是批量管理和操作一组数据,是 Python 处理多数据场景的基础。
组合数据按存储特性可分为序列、集合和映射 3 个核心类型。
- (1)序列类型:元素有序,可通过索引访问,支持切片。
- (2)集合类型:元素无序、唯一,支持集合运算(交/并/差)。
- (3)映射类型:键值对存储,通过键快速查找值。
一、列表
列表(list)是 Python 中最基础、最常用的可变序列类型,用方括号([])包裹元素,元素之间用逗号分隔,它可以存储任意类型的数据(数字、字符串、布尔值,甚至列表/字典等),且元素有序、可重复、可修改。
1. 列表的基础操作
(1)创建列表
# 空列表
empty_list = []
# 包含不同类型元素的列表
mixed_list = [1,"Python",True,3.14,[10,20]]
# 通过 list()函数创建(可将其他可迭代对象转为列表)
from_str = list("hello") # ['h','e','l','l','o']
from_range = list(range(5)) # [0,1,2,3,4]
(2)访问列表元素(索引与切片)
列表元素有序,可通过索引(从 0 开始)或切片访问,支持正向/反向索引。
- ①正向索引:list[0](第一个元素)、list[1](第二个元素)……
- ②反向索引:list[-1](最后一个)、list[-2](倒数第二个)……
- ③切片:list[起始:结束:步长](左闭右开,步长可选)。
nums = [10,20,30,40,50]
# 单个元素
print(nums[0]) # 10(正向索引)
print(nums[-1]) # 50(反向索引)
# 切片
print(nums[1:4]) # [20,30,40](索引 1 到 3)
print(nums[:3]) # [10,20,30](从开头到索引 2)
print(nums[::2]) # [10,30,50](步长 2,隔一个取一个)
(3)修改列表元素
列表是可变类型,可直接通过索引修改元素。
fruits = ["苹果","香蕉","橙子"]
fruits[1] = "葡萄" # 修改第二个元素
print(fruits) # ['苹果','葡萄','橙子']
2. 列表的常用方法
列表内置了大量方法,可用于增、删、查、改操作,具体见表 8-24 所列。
表 8-24 列表的常用方法
| 方法 | 作用 | 示例 |
|---|---|---|
| append(x) | 在列表末尾添加单个元素 x | nums.append(60)→[10,20,30,40,50,60] |
| extend(iter) | 批量添加可迭代对象的元素(如列表、字符串) | nums.extend([70,80])→[10,20,30,40,50,60,70,80] |
| insert(index,x) | 在指定索引位置插入元素 x | nums.insert(2,25)→[10,20,25,30,40,50] |
| remove(x) | 删除第一个出现的元素 x(元素不存在则报错) | nums.remove(30)→[10,20,40,50] |
| pop([index]) | 删除指定索引的元素(默认删除最后一个),并返回该元素 | nums.pop(1)→返回 20,列表变为[10,30,40,50] |
| clear() | 清空列表 | nums.clear()→[] |
| index(x) | 返回第一个出现的元素 x 的索引(不存在会报错) | nums.index(30)→2 |
| count(x) | 统计元素 x 出现的次数 | [1,2,2,3,2].count(2)→3 |
| sort([reverse=False]) | 原地排序(默认升序,reverse=True 为降序) | [3,1,2].sort()→[1,2,3] |
| reverse() | 原地反转列表 | [1,2,3].reverse()→[3,2,1] |
| copy() | 浅拷贝列表(避免修改原列表) | new_nums=nums.copy() |
# 增
nums = [10,20,30]
nums.append(40) # [10,20,30,40]
nums.extend([50,60]) # [10,20,30,40,50,60]
nums.insert(1,15) # [10,15,20,30,40,50,60]
# 删
nums.remove(30) # [10,15,20,40,50,60]
pop_num = nums.pop() # 删除最后一个元素 60,pop_num=60
nums.clear() # 清空列表→[]
# 查/统计
fruits = ["苹果","香蕉","苹果","橙子"]
print(fruits.index("苹果")) # 0
print(fruits.count("苹果")) # 2
# 排序/反转
scores = [85,92,78,90]
scores.sort() # 升序→[78,85,90,92]
scores.sort(reverse=True) # 降序→[92,90,85,78]
scores.reverse() # 反转→[78,85,90,92]
3. 列表的高级用法
(1)列表推导式
列表推导式是 Python 的特色语法,用一行代码快速生成列表,比循环更高效、简洁。
# 基本格式:[表达式 for 变量 in 可迭代对象 if 条件]
# 示例1:生成1~10的平方列表
squares = [x * x for x in range(1,11)] # [1,4,9,...,100]
# 示例2:筛选偶数
evens = [x for x in range(1,20) if x % 2 == 0] # [2,4,...,18]
(2)列表的遍历
# 遍历元素
fruits = ["苹果","香蕉","橙子"]
for fruit in fruits:
print(fruit)
(3)列表的拼接与重复
a = [1,2,3]
b = [4,5,6]
# 拼接
c = a + b # [1,2,3,4,5,6]
# 重复
d = a * 3 # [1,2,3,1,2,3,1,2,3]
二、元组
元组(tuple)是 Python 中不可变的有序序列类型,用圆括号()包裹元素(也可省略括号),元素之间用逗号分隔。它可以存储任意类型的数据(数字、字符串、列表、字典等),元素有序、可重复,但创建后无法修改元素本身(不可变是元组的核心特征)。
1. 元组的基础操作
(1)创建元组
元组的创建有多种方式,重点注意单元素元组的特殊写法(必须加逗号)。
# 空元组
empty_tuple = ()
# 多元素元组(标准写法)
num_tuple = (10,20,30,40)
# 多元素元组(省略括号:Python 仍识别为元组)
fruit_tuple = "苹果","香蕉","橙子"
# 单元素元组(必须加逗号!否则只是普通变量)
single_tuple = (50,) # 正确的单元素元组
wrong_single = (50) # 本质是整数 50,不是元组
print(type(single_tuple)) # <class 'tuple'>
print(type(wrong_single)) # <class 'int'>
# 通过 tuple()函数创建(转换其他可迭代对象)
from_list = tuple([1,2,3]) # (1,2,3)
from_str = tuple("hello") # ('h','e','l','l','o')
(2)访问元组元素(索引与切片)
元组和列表一样支持正向/反向索引和切片,二者语法完全一致(因为都是序列类型)。
t = (100,200,300,400,500)
# 单个元素访问
print(t[0]) # 100(正向索引,第一个元素)
print(t[-1]) # 500(反向索引,最后一个元素)
# 切片(左闭右开,步长可选)
print(t[1:4]) # (200,300,400)(索引 1 到 3)
print(t[::2]) # (100,300,500)(步长 2)
print(t[::-1]) # (500,400,300,200,100)(反转元组)
(3)元组的"修改"(伪修改)
元组本身不可变(无法直接修改、添加、删除元素),但如果元组中包含可变元素(如列表),那么可变元素的内部可以修改。
# 错误示例:直接修改元组元素(报错)
t1 = (1,2,3)
# t1[0] = 100 # TypeError:'tuple' object does not support item assignment
# 合法示例:修改元组中的可变元素(列表)
t2 = (1,[2,3],4)
t2[1][0] = 200 # 修改元组内列表的元素
print(t2) # (1,[200,3],4)
# 间接"修改"元组:拼接生成新元组
t3 = (10,20)
t4 = t3 + (30,40) # 生成新元组,原元组 t3 不变
print(t3) # (10,20)
print(t4) # (10,20,30,40)
2. 元组的内置方法
由于元组不可变,它的内置方法远少于列表,只有 2 个核心的内置方法,见表 8-25 所列。
表 8-25 元组的内置方法
| 方法 | 作用 | 示例 |
|---|---|---|
| index(x) | 返回第一个出现的元素 x 的索引,元素不存在则报错 | (1,2,3,2).index(2)→1 |
| count(x) | 统计元素 x 在元组中出现的次数 | (1,2,2,3,2).count(2)→3 |
t = ("苹果","香蕉","苹果","橙子","香蕉")
# 查找元素索引
print(t.index("香蕉")) # 1
# 统计元素次数
print(t.count("苹果")) # 2
3. 元组其他常用操作
(1)元组的遍历
和列表完全一致,支持直接遍历元素或遍历索引+元素。
t = ("周一","周二","周三")
# 遍历元素
for day in t:
print(day)
# 遍历索引+元素(用 enumerate)
for idx,day in enumerate(t):
print(f"索引{idx}:{day}") # 索引 0:周一,索引 1:周二...
(2)元组解包
元组解包是 Python 的便捷语法,可将元组的元素一次性赋值给多个变量,是元组最常用的场景之一。
# 基础解包
t = (18,"小明","男")
age,name,gender = t # 解包赋值
print(age) # 18
print(name) # 小明
# 扩展解包(*接收多个元素)
t2 = (1,2,3,4,5)
a,*b,c = t2 # a=1,c=5,b 接收中间所有元素
print(a) # 1
print(b) # [2,3,4](注意:*接收的结果是列表)
print(c) # 5
# 函数返回多值(本质是元组解包)
def get_info():
return "小红",20,"女" # 省略括号的元组
name,age,gender = get_info() # 解包函数返回的元组
print(f"姓名:{name},年龄:{age}")
(3)元组的拼接与重复
和列表语法一致,操作后生成新元组。
t1 = (1,2)
t2 = (3,4)
# 拼接
t3 = t1 + t2 # (1,2,3,4)
# 重复
t4 = t1 * 3 # (1,2,1,2,1,2)
三、字典
字典(dict)是 Python 中唯一的映射类型,以"键值(key-value)"对的形式存储数据,用大括号({})包裹,键和值之间用冒号(:)分隔,键值对之间用逗号(,)分隔,有以下 4 个核心特征。
- (1)键(key):唯一,不可变(只能是字符串、数字、元组等不可变类型,列表/字典等可变类型不能作为键)。
- (2)值(value):可以是任意类型(数字、字符串、列表、字典等),可重复。
- (3)有序性:Python 3.7+版本中,字典默认保留键值对的插入顺序(3.6 及以下为无序)。
- (4)可变性:可随时增、删、改键值对。
1. 字典的基础操作
(1)创建字典
字典有多种创建方式,优先掌握以下示例的前 3 种。
# 空字典
empty_dict = {}
# 标准创建(键值对形式)
user = {"name":"小明","age":18,"gender":"男"}
# 用 dict()函数创建(关键字参数)
user2 = dict(name="小红",age=20,gender="女")
# 从键值对列表创建(双值子序列)
kv_list = [("math",90),("chinese",85)]
scores = dict(kv_list) # {'math':90,'chinese':85}
# 字典推导式(高效创建,后续讲解)
num_dict = {x: x*2 for x in range(1,4)} # {1:2,2:4,3:6}
(2)访问字典的值
核心方式是通过键访问,也可通过 get()方法访问。
user = {"name":"小明","age":18}
# 方法1:直接通过键访问(键不存在会报错)
print(user["name"]) # 小明
# print(user["height"]) # KeyError:'height'
# 方法2:get()方法(键不存在返回 None 或指定默认值,推荐)
print(user.get("age")) # 18
print(user.get("height")) # None(不报错)
print(user.get("height",175)) # 175(键不存在时返回默认值)
(3)修改/添加键值对
字典的可变性主要体现在修改值、添加新键值对上,语法统一为"字典[键]=值"。
user = {"name":"小明","age":18}
# 修改已有键的值
user["age"] = 19
print(user) # {'name':'小明','age':19}
# 添加新的键值对(键不存在则自动新增)
user["height"] = 175
user["scores"] = [90,85,95]
print(user) # {'name':'小明','age':19,'height':175,'scores':[90,85,95]}
(4)删除键值对
常用的有 3 种方式,每种方式都有自己适用的场景。
user = {"name":"小明","age":18,"height":175}
# 方法1:del 语句(删除指定键值对,键不存在报错)
del user["height"]
print(user) # {'name':'小明','age':18}
# 方法2:pop()方法(删除并返回指定键的值,键不存在可指定默认值)
age = user.pop("age")
print(age) # 18(返回被删除的值)
print(user) # {'name':'小明'}
# 键不存在时指定默认值,避免报错
height = user.pop("height",0)
# 方法3:clear()方法(清空所有键值对,保留字典对象)
user.clear()
print(user) # {}
2. 字典的常用方法
字典内置了丰富的方法,其中高频使用的核心方法见表 8-26 所列。
表 8-26 字典的常用方法
| 方法 | 作用 | 示例 |
|---|---|---|
| keys() | 返回所有键的可迭代对象(dict_keys),可转列表 | user.keys()→dict_keys(['name','age']) |
| values() | 返回所有值的可迭代对象(dict_values) | user.values()→dict_values(['小明',18]) |
| items() | 返回所有键值对的可迭代对象(dict_items),每个元素是(键,值)元组 | user.items()→dict_items([('name','小明'),('age',18)]) |
| get(key,default=None) | 访问键的值,不存在返回 default | user.get('height',175)→175 |
| pop(key,default) | 删除并返回指定键的值,不存在则返回 default | user.pop('age')→18 |
| popitem() | 删除并返回最后插入的键值对(3.7+),空字典报错 | user.popitem()→('age',18) |
| update(dict) | 批量添加/修改键值对(覆盖已有键) | user.update({'age':19,'gender':'男'}) |
| clear() | 清空字典 | user.clear()→{} |
| copy() | 浅拷贝字典 | new_user = user.copy() |
user = {"name":"小明","age":18,"gender":"男"}
# 1. 获取所有键、值、键值对
print("所有键:",list(user.keys())) # ['name','age','gender']
print("所有值:",list(user.values())) # ['小明',18,'男']
print("所有键值对:",list(user.items())) # [('name','小明'),('age',18),('gender','男')]
# 2. 批量更新
user.update({"age":19,"height":175})
print("更新后:",user) # {'name':'小明','age':19,'gender':'男','height':175}
# 3. 删除最后插入的键值对
last_item = user.popitem()
print("删除的键值对:",last_item) # ('height',175)
print("删除后:",user) # {'name':'小明','age':19,'gender':'男'}
3. 字典的高级用法
(1)字典的遍历
字典遍历的核心是遍历键、值、键值对,其中遍历键值对最常用。
user = {"name":"小明","age":18,"gender":"男"}
# 方法1:遍历键(默认遍历键)
for key in user:
print(f"键:{key},值:{user[key]}")
# 方法2:遍历键值对
for key,value in user.items():
print(f"{key}:{value}")
# 方法3:只遍历值
for value in user.values():
print("值:",value)
(2)字典的嵌套
字典的值可以是任意类型,当值为字典、列表类型时,就是嵌套字典,常用于存储复杂的结构化数据。
# 嵌套字典:存储学生信息(包含成绩字典)
students = {
"小明": {
"age":18,
"gender":"男",
"scores":{"math":90,"chinese":85}
},
"小红": {
"age":17,
"gender":"女",
"scores":{"math":95,"chinese":92}
}
}
# 访问嵌套字典的值
print(students["小明"]["scores"]["math"]) # 90
# 修改嵌套字典的值
students["小红"]["age"] = 18
# 新增嵌套键值对
students["小明"]["scores"]["english"] = 88
print(students["小明"])
# {'age':18,'gender':'男','scores':{'math':90,'chinese':85,'english':88}}
四、集合
集合(set)是 Python 中无序、不重复的可变容器类型,用大括号({})包裹元素,元素之间用逗号分隔,有以下 3 个核心特征。
- (1)无序性:元素没有固定顺序,无法通过索引访问(这是与列表/元组最核心的区别)。
- (2)唯一性:自动去重,集合中不会出现重复元素。
- (3)可变性:可添加、删除元素,但集合中的元素必须是不可变类型(如数字、字符串、元组,列表/字典等可变类型不能作为集合元素)。
1. 集合的基础操作
(1)创建集合
重点注意空集合和单元素集合的创建方式,以及集合的自动去重特性。
# 空集合(必须用 set(),{}是空字典)
empty_set = set()
print(type(empty_set)) # <class 'set'>
print(type({})) # <class 'dict'>
# 普通集合(自动去重)
num_set = {1,2,2,3,3,3} # 重复元素会被自动去除
print(num_set) # {1,2,3}
# 混合类型集合(元素为不可变类型)
mix_set = {1,"python",(10,20)} # 合法
# 错误示例:包含可变元素(列表)会报错
# wrong_set = {1,[2,3]} # TypeError:unhashable type:'list'
# 通过 set()函数创建(转换其他可迭代对象)
from_list = set([1,2,2,3]) # {1,2,3}
from_str = set("hello") # {'h','e','l','o'}(自动去重 l)
from_range = set(range(5)) # {0,1,2,3,4}
(2)访问集合元素
集合无序,无法通过索引/切片访问,只能通过成员判断(in/not in)检查元素是否存在。
s = {10,20,30,40}
# 判断元素是否存在(核心访问方式)
print(20 in s) # True
print(50 not in s) # True
# 遍历集合元素(顺序不固定)
for num in s:
print(num) # 输出顺序可能是 10,30,20,40(随机)
(3)添加元素
集合提供两种添加元素的方法,分别适用于添加单个元素和批量添加元素。
s = {1,2,3}
# 方法 1:add() —— 添加单个元素(元素已存在则无操作)
s.add(4)
s.add(2) # 元素 2 已存在,无变化
print(s) # {1,2,3,4}
# 方法 2:update() —— 批量添加可迭代对象的元素(如列表、字符串、集合)
s.update([5,6]) # 添加列表元素
s.update("ab",(7,8)) # 同时添加字符串和集合元素
print(s) # {1,2,3,4,5,6,7,8,'a','b'}
(4)删除元素
集合有 4 种删除元素的方法,每种方法都有自己适用的场景。
s = {1,2,3,4,5}
# 方法 1:remove(x) —— 删除指定元素,元素不存在则报错
s.remove(3)
# s.remove(10) # KeyError:10
# 方法 2:discard(x) —— 删除指定元素,元素不存在则无操作(推荐,更安全)
s.discard(4)
s.discard(10) # 无错误,集合不变
print(s) # {1,2,5}
# 方法 3:pop() —— 随机删除并返回一个元素(集合无序,无法指定)
pop_num = s.pop()
print("删除的元素:",pop_num) # 可能是 1/2/5
print("删除后:",s)
# 方法 4:clear() —— 清空集合
s.clear()
print(s) # set()
2. 集合的核心:集合运算
集合最强大的功能是支持数学中的集合运算(交集、并集、差集、对称差集),既可以用运算符,也可以用对应的方法,具体见表 8-27 所列。
表 8-27 集合的运算方法
| 运算类型 | 运算符 | 方 法 | 含 义 | 示 例<br>(s1 = {1,2,3},s2 = {2,3,4}) |
|---|---|---|---|---|
| 并集 | \ | union() | 两个集合所有不重复的元素 | |
| 交集 | & | intersection() | 两个集合共同的元素 | s1 & s2 → {2,3} |
| 差集 | – | difference() | 属于 s1 但不属于 s2 的元素 | s1 - s2 → {1} |
| 对称差集 | ^ | symmetric_difference() | 两个集合中互不相同的元素 | s1 ^ s2 → {1,4} |
(1)基础用法
s1 = {1,2,3,4}
s2 = {3,4,5,6}
# 并集(合并所有元素,去重)
print("并集:",s1 | s2) # {1,2,3,4,5,6}
print("并集(方法):",s1.union(s2)) # 同上
# 交集(共同元素)
print("交集:",s1 & s2) # {3,4}
print("交集(方法):",s1.intersection(s2)) # 同上
# 差集(s1 有,s2 没有)
print("差集(s1-s2):",s1 - s2) # {1,2}
print("差集(方法):",s1.difference(s2)) # 同上
# 对称差集(互不相同的元素)
print("对称差集:",s1 ^ s2) # {1,2,5,6}
print("对称差集(方法):",s1.symmetric_difference(s2)) # 同上
(2)集合关系的判断
判断两个集合的包含关系,如子集、超集、不相交。
s1 = {1,2}
s2 = {1,2,3}
s3 = {4,5}
# 子集:s1 是否全部包含在 s2 中
print(s1.issubset(s2)) # True
print(s1 <= s2) # True(运算符写法)
# 超集:s2 是否包含 s1 的所有元素
print(s2.issuperset(s1)) # True
print(s2 >= s1) # True(运算符写法)