复合数据类型(容器类型)
所属模块:语法基础
难度等级:⭐️⭐️
📌 学习目标
- 掌握Python四种主要复合数据类型:列表、元组、字典和集合
- 理解每种容器类型的特点、适用场景和操作方法
- 能够根据需求选择合适的容器类型
- 学会使用容器类型的常用方法和操作
- 避免容器类型使用中的常见错误
📘 核心内容
1. 列表(list)
列表是有序、可变的元素集合,允许存储不同类型的元素,用方括号[]
表示。
# 列表定义
empty_list = [] # 空列表
numbers = [1, 2, 3, 4, 5] # 整数列表
mixed = [1, "apple", 3.14, True] # 混合类型列表
nested = [1, [2, 3], [4, [5, 6]]] # 嵌套列表
# 列表类型检查
print(type(numbers)) # 输出: <class 'list'>
# 访问列表元素(通过索引)
fruits = ["apple", "banana", "cherry"]
print(fruits[0]) # 第一个元素: "apple"
print(fruits[-1]) # 最后一个元素: "cherry"
print(nested[1][0]) # 嵌套列表访问: 2
# 修改列表元素
fruits[1] = "orange"
print(fruits) # 输出: ["apple", "orange", "cherry"]
# 列表常用操作
fruits.append("date") # 添加元素到末尾
print(fruits) # 输出: ["apple", "orange", "cherry", "date"]
fruits.insert(1, "banana") # 在指定位置插入元素
print(fruits) # 输出: ["apple", "banana", "orange", "cherry", "date"]
removed = fruits.pop(2) # 删除并返回指定位置元素
print(removed) # 输出: "orange"
print(fruits) # 输出: ["apple", "banana", "cherry", "date"]
fruits.remove("banana") # 删除第一个匹配的元素
print(fruits) # 输出: ["apple", "cherry", "date"]
# 列表切片
numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
print(numbers[2:5]) # 索引2到4: [2, 3, 4]
print(numbers[:3]) # 开始到索引2: [0, 1, 2]
print(numbers[7:]) # 索引7到结束: [7, 8, 9]
print(numbers[::2]) # 步长为2: [0, 2, 4, 6, 8]
print(numbers[::-1]) # 反转列表: [9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
💡 提示:列表是Python中最常用的容器类型,适合存储有序且需要修改的元素集合。列表的索引从0开始,使用负数索引可以从末尾开始访问元素。
2. 元组(tuple)
元组是有序、不可变的元素集合,与列表类似但元素不能修改,用圆括号()
表示。
# 元组定义
empty_tuple = () # 空元组
single_element = (5,) # 单个元素的元组(注意逗号)
numbers = (1, 2, 3, 4, 5) # 多个元素的元组
mixed = (1, "apple", 3.14, True) # 混合类型元组
nested = (1, (2, 3), (4, (5, 6))) # 嵌套元组
# 元组也可以省略括号(不推荐)
another_tuple = 10, 20, 30
# 元组类型检查
print(type(numbers)) # 输出: <class 'tuple'>
# 访问元组元素(与列表相同)
colors = ("red", "green", "blue")
print(colors[0]) # 第一个元素: "red"
print(colors[-1]) # 最后一个元素: "blue"
# 元组切片(与列表相同)
print(colors[1:3]) # 输出: ("green", "blue")
# 元组不可修改(会报错)
try:
colors[0] = "yellow"
except TypeError as e:
print(e) # 输出: 'tuple' object does not support item assignment
# 元组常用操作
print(len(colors)) # 长度: 3
print("green" in colors) # 检查包含: True
# 元组解包
a, b, c = (10, 20, 30)
print(a) # 10
print(b) # 20
print(c) # 30
# 交换变量值(利用元组解包)
x, y = 5, 10
x, y = y, x
print(x, y) # 输出: 10 5
💡 提示:元组的不可变性提供了数据安全性,适合存储不希望被修改的数据。元组比列表更节省内存,且可以作为字典的键,而列表不能。定义单个元素的元组时,必须在元素后加逗号,否则会被视为普通括号。
3. 字典(dict)
字典是无序(Python 3.7+保证插入顺序)的键值对集合,用于存储关联数据,用花括号{}
表示,键和值之间用冒号:
分隔。
# 字典定义
empty_dict = {} # 空字典
person = {
"name": "Alice",
"age": 30,
"is_student": False,
"hobbies": ["reading", "hiking"]
} # 包含多种类型值的字典
# 使用dict()构造函数创建
another_person = dict(name="Bob", age=25, is_student=True)
# 字典类型检查
print(type(person)) # 输出: <class 'dict'>
# 访问字典值(通过键)
print(person["name"]) # 输出: "Alice"
print(person.get("age")) # 输出: 30
# 使用get()方法安全访问(键不存在时返回默认值)
print(person.get("address", "Unknown")) # 输出: "Unknown"
# 修改字典值
person["age"] = 31
print(person["age"]) # 输出: 31
# 添加新键值对
person["address"] = "123 Main St"
print(person["address"]) # 输出: "123 Main St"
# 删除键值对
del person["is_student"]
print(person.get("is_student", "Not found")) # 输出: "Not found"
# 字典常用操作
print(len(person)) # 键值对数量: 4
print("name" in person) # 检查键是否存在: True
print(person.keys()) # 所有键: dict_keys(['name', 'age', 'hobbies', 'address'])
print(person.values()) # 所有值: dict_values(['Alice', 31, ['reading', 'hiking'], '123 Main St'])
print(person.items()) # 所有键值对: dict_items([('name', 'Alice'), ('age', 31), ('hobbies', ['reading', 'hiking']), ('address', '123 Main St')])
# 遍历字典
for key, value in person.items():
print(f"{key}: {value}")
💡 提示:字典的键必须是不可变类型(如整数、字符串、元组),而值可以是任何类型。使用
get()
方法访问字典比直接使用[]
更安全,因为当键不存在时不会抛出错误。
4. 集合(set)
集合是无序、不重复的元素集合,用于存储唯一元素和进行集合运算,用花括号{}
表示。
# 集合定义
empty_set = set() # 空集合(不能用{},那会创建空字典)
numbers = {1, 2, 3, 4, 5} # 数字集合
strings = {"apple", "banana", "cherry"} # 字符串集合
# 从列表创建集合(自动去重)
duplicates = [1, 2, 2, 3, 3, 3]
unique_numbers = set(duplicates)
print(unique_numbers) # 输出: {1, 2, 3}
# 集合类型检查
print(type(numbers)) # 输出: <class 'set'>
# 集合常用操作
numbers.add(6) # 添加元素
print(numbers) # 输出: {1, 2, 3, 4, 5, 6}
numbers.remove(3) # 删除元素(元素不存在会报错)
print(numbers) # 输出: {1, 2, 4, 5, 6}
numbers.discard(7) # 删除元素(元素不存在不会报错)
# 集合运算
a = {1, 2, 3, 4}
b = {3, 4, 5, 6}
print(a.union(b)) # 并集: {1, 2, 3, 4, 5, 6}
print(a.intersection(b)) # 交集: {3, 4}
print(a.difference(b)) # 差集: {1, 2}
print(a.symmetric_difference(b)) # 对称差集: {1, 2, 5, 6}
print(a.issubset(b)) # 是否为子集: False
print({3, 4}.issubset(a)) # 输出: True
# 集合遍历
for fruit in strings:
print(fruit)
💡 提示:集合的主要用途是去重和集合运算。由于集合是无序的,不能通过索引访问元素。集合中的元素必须是不可变类型,因此不能包含列表、字典或其他集合。
5. 容器类型的选择
选择合适的容器类型取决于具体需求:
# 选择指南示例
# 1. 需要有序且可修改的元素集合 → 列表
shopping_list = ["牛奶", "鸡蛋", "面包"]
shopping_list.append("水果") # 可以修改
# 2. 需要有序且不可修改的元素集合 → 元组
point = (10, 20) # 坐标点,不应该被修改
rgb_color = (255, 0, 0) # RGB颜色值
# 3. 需要存储键值对数据 → 字典
user = {
"id": 1001,
"username": "john_doe",
"email": "john@example.com"
}
# 4. 需要存储唯一元素或进行集合运算 → 集合
tags = {"python", "programming", "tutorial"}
another_tags = {"python", "beginner", "coding"}
common_tags = tags.intersection(another_tags) # 找出共同标签
各种容器类型的主要特点对比:
类型 | 有序性 | 可变性 | 元素唯一性 | 访问方式 | 适用场景 |
---|---|---|---|---|---|
列表 | 是 | 是 | 否 | 索引 | 存储有序且可能修改的元素 |
元组 | 是 | 否 | 否 | 索引 | 存储不可修改的有序数据 |
字典 | 是(3.7+) | 是 | 键唯一 | 键 | 存储键值对关联数据 |
集合 | 否 | 是 | 是 | 无索引 | 去重、集合运算 |
💡 提示:选择容器类型时,应优先考虑数据的使用方式而非数据本身。例如,即使都是数字,如果需要通过名称访问,应使用字典而非列表。
🔍 常见问题(FAQ)
Q:列表和元组有什么主要区别?
A:主要区别在于可变性:列表是可变的(可以添加、删除、修改元素),而元组是不可变的(创建后不能修改)。此外,元组比列表更节省内存,且可以作为字典的键,列表则不能。
Q:如何检查一个元素是否存在于容器中?
A:可以使用in
关键字检查元素是否存在于列表、元组、字典或集合中。对于字典,in
检查的是键而不是值,如key in my_dict
。
Q:为什么字典的键必须是不可变类型?
A:字典使用哈希表实现,键的哈希值用于快速查找。如果键是可变的,其哈希值可能会变化,导致无法正确查找。因此,只有不可变类型(如整数、字符串、元组)可以作为字典的键。
Q:集合是无序的,这意味着什么?
A:集合的无序性意味着元素没有固定的顺序,不能通过索引访问,且每次遍历的顺序可能不同。如果你需要有序且唯一的元素,可以使用collections
模块中的OrderedDict
(对于键值对)或手动维护一个列表和集合的组合。
Q:如何高效地遍历容器类型?
A:对于列表和元组,可以直接使用for item in container
;对于字典,可以使用for key in my_dict
遍历键,for value in my_dict.values()
遍历值,或for key, value in my_dict.items()
同时遍历键和值;对于集合,使用for item in my_set
遍历元素。
🏁 本节总结
- ✅ 列表(list)是有序、可变的元素集合,适合存储需要修改的序列数据
- ✅ 元组(tuple)是有序、不可变的元素集合,适合存储不希望被修改的数据
- ✅ 字典(dict)是键值对集合,适合存储关联数据,通过键快速访问
- ✅ 集合(set)是无序、唯一的元素集合,适合去重和集合运算
- ✅ 选择容器类型时应考虑数据的有序性、可变性和访问方式等需求
- ✅ 熟练掌握各种容器类型的操作方法是高效处理数据的基础