
引言:为什么需要列表和元组?
在前面的课程中,我们使用变量来存储单个数据。但如果需要存储一组数据呢?
比如:
- 存储一个班级所有学生的名字
- 存储一个月的每天温度
- 存储购物车里的所有商品
如果为每个数据创建一个变量,会非常麻烦。这时候就需要用到列表 和元组。
列表和元组都是用来存储一组数据的容器,它们的区别在于:列表可以修改,元组不能修改。
一、列表的创建和操作
1. 创建列表
列表 是Python中最常用的数据结构,用方括号 [] 表示,元素之间用逗号分隔。
python
# 创建空列表
empty_list = []
print(empty_list) # 输出:[]
# 创建包含数字的列表
numbers = [1, 2, 3, 4, 5]
print(numbers) # 输出:[1, 2, 3, 4, 5]
# 创建包含字符串的列表
fruits = ["苹果", "香蕉", "橙子"]
print(fruits) # 输出:['苹果', '香蕉', '橙子']
# 创建包含不同类型数据的列表
mixed = [1, "hello", 3.14, True]
print(mixed) # 输出:[1, 'hello', 3.14, True]
# 使用list()函数创建列表
numbers = list(range(1, 6))
print(numbers) # 输出:[1, 2, 3, 4, 5]
💡 提示:列表中的元素可以是任意类型,甚至可以嵌套列表。
2. 访问列表元素
列表中的每个元素都有一个索引(从0开始),可以通过索引访问元素。
python
fruits = ["苹果", "香蕉", "橙子", "葡萄"]
# 正向索引(从0开始)
print(fruits[0]) # 输出:苹果
print(fruits[1]) # 输出:香蕉
print(fruits[2]) # 输出:橙子
print(fruits[3]) # 输出:葡萄
# 反向索引(从-1开始)
print(fruits[-1]) # 输出:葡萄
print(fruits[-2]) # 输出:橙子
print(fruits[-3]) # 输出:香蕉
print(fruits[-4]) # 输出:苹果
⚠️ 警告 :索引超出范围会报错
IndexError
python
fruits = ["苹果", "香蕉", "橙子"]
# print(fruits[5]) # IndexError: list index out of range
3. 修改列表元素
列表是可变的,可以通过索引修改元素。
python
numbers = [1, 2, 3, 4, 5]
print(numbers) # 输出:[1, 2, 3, 4, 5]
# 修改第3个元素(索引为2)
numbers[2] = 30
print(numbers) # 输出:[1, 2, 30, 4, 5]
# 修改多个元素
numbers[0:2] = [10, 20]
print(numbers) # 输出:[10, 20, 30, 4, 5]
4. 列表切片
切片用于获取列表的一部分,语法是 list[start:end:step]。
python
numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
# 基本切片 [start:end](不包含end)
print(numbers[0:5]) # 输出:[0, 1, 2, 3, 4]
print(numbers[2:7]) # 输出:[2, 3, 4, 5, 6]
# 省略start,从开头开始
print(numbers[:5]) # 输出:[0, 1, 2, 3, 4]
# 省略end,到结尾结束
print(numbers[5:]) # 输出:[5, 6, 7, 8, 9]
# 省略start和end,复制整个列表
print(numbers[:]) # 输出:[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
# 使用步长
print(numbers[::2]) # 输出:[0, 2, 4, 6, 8]
print(numbers[1::2]) # 输出:[1, 3, 5, 7, 9]
# 反转列表
print(numbers[::-1]) # 输出:[9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
5. 列表运算
python
# 列表拼接
list1 = [1, 2, 3]
list2 = [4, 5, 6]
result = list1 + list2
print(result) # 输出:[1, 2, 3, 4, 5, 6]
# 列表重复
list1 = [1, 2, 3]
result = list1 * 3
print(result) # 输出:[1, 2, 3, 1, 2, 3, 1, 2, 3]
# 判断元素是否在列表中
fruits = ["苹果", "香蕉", "橙子"]
print("苹果" in fruits) # 输出:True
print("葡萄" in fruits) # 输出:False
print("葡萄" not in fruits) # 输出:True
6. 列表长度
python
fruits = ["苹果", "香蕉", "橙子", "葡萄"]
print(len(fruits)) # 输出:4
# 获取最后一个元素
print(fruits[len(fruits) - 1]) # 输出:葡萄
# 更简单的方式
print(fruits[-1]) # 输出:葡萄
二、列表常用方法
1. 添加元素
python
fruits = ["苹果", "香蕉"]
# append() - 在末尾添加一个元素
fruits.append("橙子")
print(fruits) # 输出:['苹果', '香蕉', '橙子']
# insert() - 在指定位置插入元素
fruits.insert(1, "葡萄")
print(fruits) # 输出:['苹果', '葡萄', '香蕉', '橙子']
# extend() - 在末尾添加多个元素
fruits.extend(["西瓜", "芒果"])
print(fruits) # 输出:['苹果', '葡萄', '香蕉', '橙子', '西瓜', '芒果']
# 使用 + 运算符
fruits = fruits + ["草莓"]
print(fruits) # 输出:['苹果', '葡萄', '香蕉', '橙子', '西瓜', '芒果', '草莓']
2. 删除元素
python
fruits = ["苹果", "香蕉", "橙子", "葡萄", "西瓜"]
# remove() - 删除第一个匹配的元素
fruits.remove("香蕉")
print(fruits) # 输出:['苹果', '橙子', '葡萄', '西瓜']
# pop() - 删除指定位置的元素,并返回该元素
removed = fruits.pop(1)
print(removed) # 输出:橙子
print(fruits) # 输出:['苹果', '葡萄', '西瓜']
# pop() - 不指定位置,默认删除最后一个
removed = fruits.pop()
print(removed) # 输出:西瓜
print(fruits) # 输出:['苹果', '葡萄']
# del - 删除指定位置的元素
del fruits[0]
print(fruits) # 输出:['葡萄']
# clear() - 清空列表
fruits.clear()
print(fruits) # 输出:[]
💡 提示:
remove()删除第一个匹配的元素,如果元素不存在会报错pop()返回被删除的元素,remove()不返回
3. 查找元素
python
fruits = ["苹果", "香蕉", "橙子", "香蕉", "葡萄"]
# index() - 查找元素的索引(第一个匹配)
print(fruits.index("香蕉")) # 输出:1
# 指定查找范围
print(fruits.index("香蕉", 2)) # 输出:3(从索引2开始查找)
# count() - 统计元素出现的次数
print(fruits.count("香蕉")) # 输出:2
print(fruits.count("苹果")) # 输出:1
print(fruits.count("西瓜")) # 输出:0
# in - 判断元素是否存在
print("香蕉" in fruits) # 输出:True
print("西瓜" in fruits) # 输出:False
4. 排序
python
numbers = [3, 1, 4, 1, 5, 9, 2, 6, 5]
# sort() - 原地排序(修改原列表)
numbers.sort()
print(numbers) # 输出:[1, 1, 2, 3, 4, 5, 5, 6, 9]
# 降序排序
numbers.sort(reverse=True)
print(numbers) # 输出:[9, 6, 5, 5, 4, 3, 2, 1, 1]
# sorted() - 返回新列表,不修改原列表
numbers = [3, 1, 4, 1, 5, 9, 2, 6, 5]
new_list = sorted(numbers)
print(numbers) # 输出:[3, 1, 4, 1, 5, 9, 2, 6, 5](原列表不变)
print(new_list) # 输出:[1, 1, 2, 3, 4, 5, 5, 6, 9]
# 反转列表
numbers.reverse()
print(numbers) # 输出:[5, 6, 2, 9, 5, 1, 4, 1, 3]
# 使用 [::-1] 反转(不修改原列表)
numbers = [1, 2, 3, 4, 5]
reversed_list = numbers[::-1]
print(numbers) # 输出:[1, 2, 3, 4, 5]
print(reversed_list) # 输出:[5, 4, 3, 2, 1]
5. 复制列表
python
# 使用 copy() 方法
fruits = ["苹果", "香蕉", "橙子"]
fruits_copy = fruits.copy()
print(fruits_copy) # 输出:['苹果', '香蕉', '橙子']
# 使用切片
fruits_copy = fruits[:]
print(fruits_copy) # 输出:['苹果', '香蕉', '橙子']
# 使用 list() 函数
fruits_copy = list(fruits)
print(fruits_copy) # 输出:['苹果', '香蕉', '橙子']
# ⚠️ 注意:直接赋值不是复制
fruits = ["苹果", "香蕉", "橙子"]
fruits_ref = fruits # 这只是引用,不是复制
fruits_ref.append("葡萄")
print(fruits) # 输出:['苹果', '香蕉', '橙子', '葡萄'](原列表也被修改了)
6. 列表推导式
列表推导式是创建列表的简洁方式。
python
# 基本语法:[表达式 for 变量 in 序列]
# 创建1到10的平方列表
squares = [x**2 for x in range(1, 11)]
print(squares) # 输出:[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
# 筛选偶数
evens = [x for x in range(1, 21) if x % 2 == 0]
print(evens) # 输出:[2, 4, 6, 8, 10, 12, 14, 16, 18, 20]
# 字符串处理
words = ["hello", "world", "python"]
upper_words = [word.upper() for word in words]
print(upper_words) # 输出:['HELLO', 'WORLD', 'PYTHON']
# 嵌套列表
matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
flat = [num for row in matrix for num in row]
print(flat) # 输出:[1, 2, 3, 4, 5, 6, 7, 8, 9]
💡 提示:列表推导式比等价的for循环更简洁,执行速度也更快。
三、元组的特点
1. 什么是元组
元组 与列表类似,但元组是不可变的,用圆括号 () 表示。
python
# 创建元组
empty_tuple = ()
print(empty_tuple) # 输出:()
# 创建包含元素的元组
numbers = (1, 2, 3, 4, 5)
print(numbers) # 输出:(1, 2, 3, 4, 5)
# 创建包含不同类型数据的元组
mixed = (1, "hello", 3.14, True)
print(mixed) # 输出:(1, 'hello', 3.14, True)
# 创建单个元素的元组(注意逗号)
single = (5,) # 必须有逗号
print(single) # 输出:(5,)
print(type(single)) # 输出:<class 'tuple'>
# 没有逗号的情况
not_tuple = (5)
print(not_tuple) # 输出:5
print(type(not_tuple)) # 输出:<class 'int'>
💡 提示:创建单个元素的元组时,必须加逗号,否则Python会把它当作普通数据类型。
2. 元组的不可变性
元组创建后不能修改,这是元组和列表的最大区别。
python
# 列表可以修改
fruits = ["苹果", "香蕉", "橙子"]
fruits[0] = "葡萄"
print(fruits) # 输出:['葡萄', '香蕉', '橙子']
# 元组不能修改
numbers = (1, 2, 3, 4, 5)
# numbers[0] = 10 # TypeError: 'tuple' object does not support item assignment
💡 提示:元组的不可变性使得它比列表更安全,可以作为字典的键。
3. 元组的操作
虽然元组不能修改,但可以进行一些操作。
python
numbers = (1, 2, 3, 4, 5, 2, 3)
# 访问元素
print(numbers[0]) # 输出:1
print(numbers[-1]) # 输出:3
# 切片
print(numbers[1:4]) # 输出:(2, 3, 4)
# 长度
print(len(numbers)) # 输出:7
# 计数
print(numbers.count(2)) # 输出:2
# 查找索引
print(numbers.index(3)) # 输出:2
# 判断元素是否存在
print(3 in numbers) # 输出:True
print(10 in numbers) # 输出:False
4. 元组的解包
元组解包是Python的一个强大特性。
python
# 基本解包
point = (3, 4)
x, y = point
print(x) # 输出:3
print(y) # 输出:4
# 交换变量
a = 1
b = 2
a, b = b, a
print(a) # 输出:2
print(b) # 输出:1
# 使用 * 收集剩余元素
numbers = (1, 2, 3, 4, 5)
first, *rest = numbers
print(first) # 输出:1
print(rest) # 输出:[2, 3, 4, 5]
first, second, *rest = numbers
print(first) # 输出:1
print(second) # 输出:2
print(rest) # 输出:[3, 4, 5]
# 在函数返回值中使用
def get_min_max(numbers):
return min(numbers), max(numbers)
minimum, maximum = get_min_max([3, 1, 4, 1, 5, 9, 2, 6])
print(f"最小值:{minimum},最大值:{maximum}")
5. 元组与列表的转换
python
# 列表转元组
fruits_list = ["苹果", "香蕉", "橙子"]
fruits_tuple = tuple(fruits_list)
print(fruits_tuple) # 输出:('苹果', '香蕉', '橙子')
# 元组转列表
numbers_tuple = (1, 2, 3, 4, 5)
numbers_list = list(numbers_tuple)
print(numbers_list) # 输出:[1, 2, 3, 4, 5]
# 修改"元组"的技巧:转换为列表,修改后再转回元组
numbers = (1, 2, 3, 4, 5)
numbers_list = list(numbers)
numbers_list[0] = 10
numbers = tuple(numbers_list)
print(numbers) # 输出:(10, 2, 3, 4, 5)
6. 元组的使用场景
python
# 1. 函数返回多个值
def get_user_info():
name = "小明"
age = 25
city = "北京"
return name, age, city # 返回元组
name, age, city = get_user_info()
print(f"姓名:{name},年龄:{age},城市:{city}")
# 2. 作为字典的键(列表不能作为字典的键)
locations = {
(39.9, 116.4): "北京",
(31.2, 121.5): "上海",
(23.1, 113.3): "广州"
}
print(locations[(39.9, 116.4)]) # 输出:北京
# 3. 数据不可变的场景
RGB_RED = (255, 0, 0)
RGB_GREEN = (0, 255, 0)
RGB_BLUE = (0, 0, 255)
# 4. 命名元组(更高级的用法)
from collections import namedtuple
Point = namedtuple('Point', ['x', 'y'])
p = Point(3, 4)
print(p.x) # 输出:3
print(p.y) # 输出:4
四、列表与元组的对比
| 特性 | 列表 | 元组 |
|---|---|---|
| 符号 | [] |
() |
| 可变性 | 可变 | 不可变 |
| 性能 | 较慢 | 较快 |
| 内存占用 | 较大 | 较小 |
| 可作为字典键 | 不可以 | 可以 |
| 适用场景 | 数据需要修改 | 数据不需要修改 |
python
# 性能对比
import sys
# 列表
list_example = [1, 2, 3, 4, 5]
print(f"列表大小:{sys.getsizeof(list_example)} bytes")
# 元组
tuple_example = (1, 2, 3, 4, 5)
print(f"元组大小:{sys.getsizeof(tuple_example)} bytes")
💡 提示:如果数据不需要修改,优先使用元组,因为它更节省内存,执行速度也更快。
五、实战练习
练习1:学生成绩管理
python
# 存储学生成绩
students = [
("张三", 85),
("李四", 92),
("王五", 78),
("赵六", 95),
("钱七", 88)
]
# 计算平均分
total = sum(score for name, score in students)
average = total / len(students)
print(f"平均分:{average:.1f}")
# 找出最高分和最低分
highest = max(students, key=lambda x: x[1])
lowest = min(students, key=lambda x: x[1])
print(f"最高分:{highest[0]}({highest[1]}分)")
print(f"最低分:{lowest[0]}({lowest[1]}分)")
# 按成绩排序
sorted_students = sorted(students, key=lambda x: x[1], reverse=True)
print("\n成绩排名:")
for i, (name, score) in enumerate(sorted_students, 1):
print(f"{i}. {name}:{score}分")
练习2:购物车管理
python
# 购物车
cart = []
# 添加商品
def add_item(name, price, quantity=1):
cart.append((name, price, quantity))
print(f"已添加:{name},单价:{price},数量:{quantity}")
# 删除商品
def remove_item(name):
for i, item in enumerate(cart):
if item[0] == name:
cart.pop(i)
print(f"已删除:{name}")
return
print(f"未找到:{name}")
# 计算总价
def total_price():
total = sum(price * quantity for name, price, quantity in cart)
return total
# 显示购物车
def show_cart():
if not cart:
print("购物车为空")
return
print("\n购物车内容:")
print("-" * 40)
for name, price, quantity in cart:
print(f"{name}:{price}元 × {quantity} = {price * quantity}元")
print("-" * 40)
print(f"总计:{total_price()}元")
# 测试
add_item("苹果", 5.5, 3)
add_item("香蕉", 3.0, 2)
add_item("橙子", 4.5, 1)
show_cart()
remove_item("香蕉")
show_cart()
练习3:矩阵转置
python
# 原始矩阵
matrix = [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9]
]
# 方法1:使用列表推导式
transposed = [[matrix[j][i] for j in range(len(matrix))] for i in range(len(matrix[0]))]
print("原始矩阵:")
for row in matrix:
print(row)
print("\n转置后:")
for row in transposed:
print(row)
# 方法2:使用zip()
transposed = list(zip(*matrix))
print("\n使用zip()转置:")
for row in transposed:
print(row)
练习4:统计词频
python
# 文本
text = """
Python是一种广泛使用的高级编程语言。
Python的设计哲学强调代码的可读性和简洁的语法。
Python支持多种编程范式,包括面向对象、命令式、函数式和过程式编程。
"""
# 统计词频
words = text.replace("。", "").replace(",", "").replace("、", "").split()
word_count = {}
for word in words:
if word in word_count:
word_count[word] += 1
else:
word_count[word] = 1
# 按频率排序
sorted_words = sorted(word_count.items(), key=lambda x: x[1], reverse=True)
print("词频统计:")
for word, count in sorted_words[:10]:
print(f"{word}:{count}次")
六、常见问题与排错
问题1:索引超出范围
原因 :访问了不存在的索引 解决方法:确保索引在有效范围内
python
fruits = ["苹果", "香蕉", "橙子"]
# print(fruits[5]) # IndexError: list index out of range
# 正确做法:先检查长度
if len(fruits) > 5:
print(fruits[5])
else:
print("索引超出范围")
问题2:修改元组报错
原因 :元组是不可变的 解决方法:如果需要修改,使用列表
python
numbers = (1, 2, 3)
# numbers[0] = 10 # TypeError
# 如果需要修改,转换为列表
numbers_list = list(numbers)
numbers_list[0] = 10
numbers = tuple(numbers_list)
问题3:列表引用问题
原因 :直接赋值只是创建引用,不是复制 解决方法:使用 copy() 或切片
python
# ❌ 错误
list1 = [1, 2, 3]
list2 = list1 # 只是引用
list2.append(4)
print(list1) # 输出:[1, 2, 3, 4](list1也被修改了)
# ✅ 正确
list1 = [1, 2, 3]
list2 = list1.copy() # 或 list1[:]
list2.append(4)
print(list1) # 输出:[1, 2, 3](list1不变)
print(list2) # 输出:[1, 2, 3, 4]
七、本篇小结
今天,我们完成了以下学习内容:
-
列表的创建和操作:
- 使用
[]创建列表 - 通过索引访问和修改元素
- 列表切片
- 列表运算(拼接、重复、判断)
- 使用
-
列表常用方法:
- 添加:append()、insert()、extend()
- 删除:remove()、pop()、del、clear()
- 查找:index()、count()、in
- 排序:sort()、sorted()、reverse()
- 复制:copy()、切片、list()
-
元组的特点:
- 使用
()创建元组 - 元组是不可变的
- 元组解包
- 元组与列表的转换
- 元组的使用场景
- 使用
请记住这三个结论:
- 列表是可变的:适合存储需要修改的数据
- 元组是不可变的:适合存储不需要修改的数据,更安全、更高效
- 列表推导式很强大:用简洁的方式创建和处理列表
下期预告
在第7期中,我们将学习Python的字典和集合,包括:
- 字典的创建和基本操作
- 字典的常用方法
- 集合的概念和操作
- 字典和集合的应用场景
敬请期待!
✍坚持原创,求关注,点赞,收藏