列表
# 列表(List)
# 1. 列表的核心概念
列表(List)是 Python 中最基础、最强大的数据结构之一。你可以把它想象成一个有序的货架,上面可以按顺序存放任何东西。
列表具有三大核心特性:
- 有序 (Ordered): 列表中的每个元素都有一个固定的、从0开始的索引(位置编号)。这个顺序不会改变,除非你主动修改它。
- 可变 (Mutable): 你可以在列表创建后,随时修改它的内容,比如添加、删除或更改元素。这是它与字符串和元组最本质的区别。
- 异构 (Heterogeneous): 列表可以包含任意类型的元素,包括数字、字符串、布尔值,甚至其他列表。
# 2. 创建列表
# 2.1 使用方括号 []
这是最常见、最直接的创建方式。
# 创建一个空列表
empty_list = []
print(f"空列表: {empty_list}") # 输出: 空列表: []
# 创建一个包含整数的列表
numbers = [1, 2, 3, 4, 5]
print(f"数字列表: {numbers}") # 输出: 数字列表: [1, 2, 3, 4, 5]
# 创建一个包含字符串的列表
fruits = ["apple", "banana", "cherry"]
print(f"水果列表: {fruits}") # 输出: 水果列表: ['apple', 'banana', 'cherry']
# 创建一个混合类型的列表
mixed_list = [1, "hello", 3.14, True, None]
print(f"混合列表: {mixed_list}") # 输出: 混合列表: [1, 'hello', 3.14, True, None]
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 2.2 使用 list()
构造函数
list()
函数可以将任何可迭代对象(如字符串、元组、集合、range对象等)转换为列表。
# 从字符串创建列表
char_list = list("hello")
print(f"从字符串转换: {char_list}") # 输出: 从字符串转换: ['h', 'e', 'l', 'l', 'o']
# 从元组创建列表
tuple_data = (10, 20, 30)
list_from_tuple = list(tuple_data)
print(f"从元组转换: {list_from_tuple}") # 输出: 从元组转换: [10, 20, 30]
# 从 range 对象创建列表
even_numbers = list(range(0, 10, 2))
print(f"从range转换: {even_numbers}") # 输出: 从range转换: [0, 2, 4, 6, 8]
2
3
4
5
6
7
8
9
10
11
12
# 3. 访问与切片:查询列表内容
# 3.1 访问单个元素 (索引)
使用方括号 []
和索引值来访问列表中的特定元素。
fruits = ["apple", "banana", "cherry", "date"]
# 正向索引 (从 0 开始)
print(f"第一个水果 (fruits[0]): {fruits[0]}") # 输出: 第一个水果 (fruits[0]): apple
# 负向索引 (从 -1 开始)
print(f"最后一个水果 (fruits[-1]): {fruits[-1]}") # 输出: 最后一个水果 (fruits[-1]): date
2
3
4
5
6
7
# 3.2 遍历列表
使用 for
循环可以依次访问列表中的每一个元素。
for fruit in fruits:
print(f"我喜欢吃 {fruit}")
# 输出:
# 我喜欢吃 apple
# 我喜欢吃 banana
# 我喜欢吃 cherry
# 我喜欢吃 date
2
3
4
5
6
7
# 3.3 切片:获取子列表
切片(Slicing)可以让你获取列表的一部分,它返回一个新的列表。
numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
# 获取从索引 1 到 4 的元素 (不包含索引5)
print(f"numbers[1:5] -> {numbers[1:5]}") # 输出: numbers[1:5] -> [1, 2, 3, 4]
# 从开头到索引 4
print(f"numbers[:5] -> {numbers[:5]}") # 输出: numbers[:5] -> [0, 1, 2, 3, 4]
# 从索引 5 到末尾
print(f"numbers[5:] -> {numbers[5:]}") # 输出: numbers[5:] -> [5, 6, 7, 8, 9]
# 带步长的切片 (每隔一个取一个)
print(f"numbers[::2] -> {numbers[::2]}") # 输出: numbers[::2] -> [0, 2, 4, 6, 8]
# 反转列表 (一个非常常用的技巧)
print(f"numbers[::-1] -> {numbers[::-1]}") # 输出: numbers[::-1] -> [9, 8, 7, 6, 5, 4, 3, 2, 1]
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 4. 添加与修改元素
# 4.1 修改单个元素
直接通过索引赋值即可。
fruits = ["apple", "banana", "cherry"]
print(f"修改前: {fruits}") # 输出: 修改前: ['apple', 'banana', 'cherry']
fruits[1] = "blueberry" # 将 'banana' 修改为 'blueberry'
print(f"修改后: {fruits}") # 输出: 修改后: ['apple', 'blueberry', 'cherry']
2
3
4
5
# 4.2 添加元素
# append()
: 在列表末尾添加单个元素
这是最常用的添加方法。
numbers = [1, 2, 3]
numbers.append(4)
print(f"append(4) 之后: {numbers}") # 输出: append(4) 之后: [1, 2, 3, 4]
2
3
# extend()
: 将一个可迭代对象的所有元素添加到列表末尾
extend()
会把新列表中的元素一个个地“扩展”进原列表。
list_a = [1, 2, 3]
list_b = [4, 5, 6]
list_a.extend(list_b)
print(f"extend(list_b) 之后: {list_a}") # 输出: extend(list_b) 之后: [1, 2, 3, 4, 5, 6]
2
3
4
新手陷阱:
append()
vsextend()
append()
把传入的对象当作一个整体添加,而extend()
会遍历传入的对象,将其元素逐个添加。my_list = [1, 2] my_list.append([3, 4]) print(my_list) # 输出: [1, 2, [3, 4]] (列表里嵌套了另一个列表) my_list = [1, 2] my_list.extend([3, 4]) print(my_list) # 输出: [1, 2, 3, 4] (这通常是你想要的结果)
1
2
3
4
5
6
7
# insert()
: 在指定位置插入单个元素
insert(index, element)
将元素插入到指定的索引 index
之前。
numbers = [10, 20, 40, 50]
numbers.insert(2, 30) # 在索引 2 的位置插入 30
print(f"insert(2, 30) 之后: {numbers}") # 输出: insert(2, 30) 之后: [10, 20, 30, 40, 50]
2
3
# 5. 删除元素
# 5.1 remove()
: 按值删除
remove(value)
会从列表中删除第一个匹配到的 value
。如果值不存在,会抛出 ValueError
。
fruits = ["apple", "banana", "cherry", "banana"]
fruits.remove("banana") # 只会删除第一个 "banana"
print(f"remove('banana') 之后: {fruits}") # 输出: remove('banana') 之后: ['apple', 'cherry', 'banana']
2
3
# 5.2 pop()
: 按索引删除
pop(index=-1)
会删除并返回指定索引处的元素。如果 index
未指定,则默认删除并返回最后一个元素。
numbers = [1, 2, 3, 4, 5]
# 弹出最后一个元素
last_item = numbers.pop()
print(f"弹出的元素: {last_item}") # 输出: 弹出的元素: 5
print(f"pop() 之后的列表: {numbers}") # 输出: pop() 之后的列表: [1, 2, 3, 4]
# 弹出索引为 1 的元素
item_at_1 = numbers.pop(1)
print(f"弹出的元素: {item_at_1}") # 输出: 弹出的元素: 2
print(f"pop(1) 之后的列表: {numbers}") # 输出: pop(1) 之后的列表: [1, 3, 4]
2
3
4
5
6
7
8
9
10
11
# 5.3 del
关键字: 更强大的删除
del
是一个 Python 关键字,可以删除指定索引的元素,或通过切片删除一段元素。
numbers = list(range(10)) # [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
# 删除索引为 0 的元素
del numbers[0]
print(f"删除索引0后: {numbers}") # 输出: 删除索引0后: [1, 2, 3, 4, 5, 6, 7, 8, 9]
# 删除一个切片 (从索引2到索引4)
del numbers[2:5]
print(f"删除切片后: {numbers}") # 输出: 删除切片后: [1, 2, 6, 7, 8, 9]
2
3
4
5
6
7
8
9
# 5.4 clear()
: 清空整个列表
clear()
会删除列表中的所有元素,使其变为空列表 []
。
items = [1, 2, 3]
items.clear()
print(f"clear() 之后: {items}") # 输出: clear() 之后: []
2
3
删除方法对比:
- 想按值删除,用
remove()
。- 想按索引删除,并需要用到被删除的元素,用
pop()
。- 想按索引或切片删除,且不需要被删除的元素,用
del
。- 想清空整个列表,用
clear()
。
# 6. 列表排序与反转
# 6.1 sort()
方法: 原地排序
list.sort()
会直接修改原始列表,使其有序。
reverse=False
(默认): 升序排序。reverse=True
: 降序排序。
numbers = [3, 1, 4, 1, 5, 9, 2]
numbers.sort()
print(f"升序排序后: {numbers}") # 输出: 升序排序后: [1, 1, 2, 3, 4, 5, 9]
numbers.sort(reverse=True)
print(f"降序排序后: {numbers}") # 输出: 降序排序后: [9, 5, 4, 3, 2, 1, 1]
2
3
4
5
6
# 6.2 sorted()
函数: 返回新列表
sorted(iterable)
是一个内置函数,它会返回一个新的排好序的列表,而不改变原始的可迭代对象。
numbers = [3, 1, 4, 1, 5, 9, 2]
sorted_list = sorted(numbers)
print(f"原始列表: {numbers}") # 输出: 原始列表: [3, 1, 4, 1, 5, 9, 2] (未改变)
print(f"排序后的新列表: {sorted_list}") # 输出: 排序后的新列表: [1, 1, 2, 3, 4, 5, 9]
2
3
4
5
# 6.3 key
参数: 自定义排序规则
sort()
和 sorted()
都接受一个 key
参数,你可以提供一个函数,排序时会根据每个元素经过该函数计算后的结果来进行。
# 按字符串长度排序
words = ["apple", "banana", "cherry", "date"]
words.sort(key=len)
print(f"按长度排序: {words}") # 输出: 按长度排序: ['date', 'apple', 'banana', 'cherry']
# 按学生年龄排序 (列表元素是字典)
students = [
{"name": "Alice", "age": 25},
{"name": "Bob", "age": 20},
{"name": "Charlie", "age": 22}
]
# 使用 lambda 函数指定按 'age' 键的值排序
sorted_students = sorted(students, key=lambda s: s['age'])
print(f"按年龄排序的学生: {sorted_students}")
# 输出: 按年龄排序的学生: [{'name': 'Bob', 'age': 20}, {'name': 'Charlie', 'age': 22}, {'name': 'Alice', 'age': 25}]
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 6.4 reverse()
方法: 原地反转
list.reverse()
会直接修改原始列表,将其元素顺序完全颠倒。
items = [1, 'a', 2, 'b']
items.reverse()
print(f"反转后: {items}") # 输出: 反转后: ['b', 2, 'a', 1]
2
3
注意:
reverse()
只是简单地反转位置,并不进行排序。
# 7. 其他常用列表操作
# 7.1 len()
: 获取列表长度
print(f"列表 [1, 2, 3] 的长度是: {len([1, 2, 3])}") # 输出: 列表 [1, 2, 3] 的长度是: 3
# 7.2 in
和 not in
: 成员检测
fruits = ["apple", "banana", "cherry"]
print(f"'banana' 是否在列表中? {'banana' in fruits}") # 输出: 'banana' 是否在列表中? True
print(f"'grape' 是否不在列表中? {'grape' not in fruits}") # 输出: 'grape' 是否不在列表中? True
2
3
# 7.3 count()
: 统计元素出现次数
numbers = [1, 2, 2, 3, 2, 4]
print(f"数字 2 出现了 {numbers.count(2)} 次") # 输出: 数字 2 出现了 3 次
2
# 7.4 index()
: 查找元素索引
numbers = [10, 20, 30, 40, 20]
# 只返回第一个匹配项的索引
print(f"数字 20 的索引是: {numbers.index(20)}") # 输出: 数字 20 的索引是: 1
2
3
# 8. 列表推导式 (List Comprehension)
列表推导式是一种极其强大且“Pythonic”的语法,可以用一行代码优雅地创建列表。
基本语法: [expression for item in iterable]
# 创建 0-9 的平方数列表
squares = [x**2 for x in range(10)]
print(f"平方数列表: {squares}") # 输出: 平方数列表: [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
2
3
带 if
条件: [expression for item in iterable if condition]
# 创建 0-9 中的偶数列表
even_numbers = [x for x in range(10) if x % 2 == 0]
print(f"偶数列表: {even_numbers}") # 输出: 偶数列表: [0, 2, 4, 6, 8]
2
3
带 if-else
: [expr_if_true if condition else expr_if_false for item in iterable]
# 将数字标记为 '偶数' 或 '奇数'
labels = ['偶数' if x % 2 == 0 else '奇数' for x in range(10)]
print(f"标签列表: {labels}")
# 输出: 标签列表: ['偶数', '奇数', '偶数', '奇数', '偶数', '奇数', '偶数', '奇数', '偶数', '奇数']
2
3
4
列表推导式不仅代码更短,通常运行速度也比等效的
for
循环更快。
# 9. 嵌套列表:处理二维数据
列表可以包含其他列表,形成嵌套结构,常用于表示矩阵或二维表格。
# 一个 3x3 的矩阵
matrix = [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9]
]
# 访问第一行
print(f"第一行: {matrix[0]}") # 输出: 第一行: [1, 2, 3]
# 访问第二行第三个元素 (索引是 [1][2])
element = matrix[1][2]
print(f"第二行第三列的元素: {element}") # 输出: 第二行第三列的元素: 6
2
3
4
5
6
7
8
9
10
11
12
13
# 10. 列表的复制:浅拷贝与深拷贝
这是一个非常重要的概念,常常是新手出错的根源。
# 10.1 赋值:只是贴了个新标签
当你写 b = a
时,你没有创建新列表,只是让变量 b
指向了 a
所指向的同一个列表对象。
a = [1, 2, 3]
b = a
b[0] = 99
print(f"修改 b 后, a 的值: {a}") # 输出: 修改 b 后, a 的值: [99, 2, 3] (a 也被修改了!)
print(f"a 和 b 的内存地址是否相同? {id(a) == id(b)}") # 输出: a 和 b 的内存地址是否相同? True
2
3
4
5
# 10.2 浅拷贝: copy()
或 [:]
浅拷贝会创建一个新的顶层列表,但如果列表内包含其他可变对象(如另一个列表),它只会复制这些对象的引用。
original = [1, [10, 20], 3]
shallow_copy = original.copy() # 或者 shallow_copy = original[:]
shallow_copy[0] = 99 # 修改顶层元素,不影响原始列表
shallow_copy[1][0] = 999 # 修改嵌套列表的元素,会影响原始列表!
print(f"原始列表: {original}") # 输出: 原始列表: [1, [999, 20], 3] (被意外修改了!)
print(f"浅拷贝列表: {shallow_copy}") # 输出: 浅拷贝列表: [99, [999, 20], 3]
2
3
4
5
6
7
8
# 10.3 深拷贝: copy.deepcopy()
深拷贝会递归地复制所有层级的元素,创建一个与原始对象完全独立的全新对象。
import copy
original = [1, [10, 20], 3]
deep_copy = copy.deepcopy(original)
deep_copy[0] = 99 # 不影响
deep_copy[1][0] = 999 # 不影响
print(f"原始列表: {original}") # 输出: 原始列表: [1, [10, 20], 3] (安全,未被修改)
print(f"深拷贝列表: {deep_copy}") # 输出: 深拷贝列表: [99, [999, 20], 3]
2
3
4
5
6
7
8
9
10
何时使用:
- 如果你的列表只包含数字、字符串等不可变类型,使用浅拷贝就足够了。
- 如果你的列表包含其他列表或字典等可变类型,为了安全起见,请使用深拷贝。