列表 (List)
理解列表创建、索引、切片、增删改查等常用操作
Python 列表 (List)
列表是 Python 中最常用的数据结构。它是有序、可变的集合,用方括号 [] 表示。
学完本章你将掌握: 创建列表、索引切片、增删改查、排序、列表推导式,以及 12+ 个常用方法。
一、创建列表
列表可以存放任意类型的数据,甚至混合类型:
# 空列表
empty = []
# 数字列表
numbers = [1, 2, 3, 4, 5]
# 字符串列表
fruits = ["苹果", "香蕉", "橘子"]
# 混合类型(不推荐,但语法允许)
mixed = [1, "hello", True, 3.14, [1, 2]]
# list() 构造函数
chars = list("hello")
print(chars) # ['h', 'e', 'l', 'l', 'o']
💡 你知道吗:
list(range(1, 101))可以快速生成 1 到 100 的数字列表,比手写快得多。
二、索引——访问元素
列表索引从 0 开始,负数索引从末尾倒数:
colors = ["红", "橙", "黄", "绿", "蓝", "靛", "紫"]
print(colors[0]) # 红 — 第一个
print(colors[1]) # 橙
print(colors[3]) # 绿
print(colors[-1]) # 紫 — 最后一个
print(colors[-2]) # 靛 — 倒数第二个
print(colors[-3]) # 蓝
# 索引越界会报错 IndexError
# print(colors[10]) # ❌ IndexError: list index out of range
检查列表是否为空 是常见的需求:
items = []
if not items:
print("列表为空")
if items:
print("列表有内容")
三、切片——获取子列表
切片语法:list[start:end:step],包含 start,不包含 end:
nums = [0, 10, 20, 30, 40, 50, 60, 70, 80, 90]
# 基本切片
print(nums[2:5]) # [20, 30, 40] 索引 2,3,4
print(nums[:4]) # [0, 10, 20, 30] 从头到索引3
print(nums[6:]) # [60, 70, 80, 90] 索引6到末尾
print(nums[:]) # [0,10,20,...,90] 复制整个列表
# 步长
print(nums[::2]) # [0, 20, 40, 60, 80] 每隔一个
print(nums[1::2]) # [10, 30, 50, 70, 90] 从索引1每隔一个
print(nums[::-1]) # [90, 80, ..., 0] 反转列表
# 倒数切片
print(nums[-5:-2]) # [50, 60, 70] 倒数第5到倒数第2
print(nums[-3:]) # [70, 80, 90] 最后3个
💡 你知道吗:
nums[::-1]是反转列表的经典写法,但它创建新列表,不修改原列表。要原地反转用nums.reverse()。
四、修改元素
列表是可变的,可以直接通过索引修改:
colors = ["红", "绿", "蓝"]
# 修改单个元素
colors[1] = "黄"
print(colors) # ['红', '黄', '蓝']
# 批量替换(切片赋值)
colors = ["红", "橙", "黄", "绿", "蓝"]
colors[1:4] = ["粉", "紫"] # 把索引1~3替换为2个元素
print(colors) # ['红', '粉', '紫', '蓝']
五、添加元素
三种主要添加方式,各有用途:
fruits = ["苹果", "香蕉"]
# append() — 末尾添加一个元素(最常用)
fruits.append("橘子")
print(fruits) # ['苹果', '香蕉', '橘子']
# insert() — 在指定位置插入
fruits.insert(1, "葡萄") # 在索引1处插入
print(fruits) # ['苹果', '葡萄', '香蕉', '橘子']
# extend() — 合并另一个列表
more = ["西瓜", "草莓"]
fruits.extend(more)
print(fruits) # ['苹果', '葡萄', '香蕉', '橘子', '西瓜', '草莓']
💡 你知道吗:
extend(list)比for x in list: append(x)快得多,因为 extend 是一次性批量添加。
六、删除元素
多种删除方法,按场景选择:
items = ["a", "b", "c", "d", "e", "b"]
# pop() — 删除并返回指定位置元素(默认删除最后一个)
last = items.pop()
print(last) # b
print(items) # ['a', 'b', 'c', 'd', 'e']
second = items.pop(1) # 删除索引1
print(second) # b
print(items) # ['a', 'c', 'd', 'e']
# remove() — 按值删除(只删第一个匹配的)
nums = [1, 2, 3, 2, 4]
nums.remove(2)
print(nums) # [1, 3, 2, 4] 只删了第一个2
# del — 按索引删除(不返回值)
del nums[0]
print(nums) # [3, 2, 4]
del nums[1:3] # 删除切片
print(nums) # [3]
# clear() — 清空整个列表
nums.clear()
print(nums) # []
💡 常见陷阱:
remove(2)如果没有找到元素 2,会抛出ValueError。不确定是否存在时先判断if 2 in nums: nums.remove(2)。
七、查——查找与统计
fruits = ["苹果", "香蕉", "橘子", "香蕉", "葡萄"]
# len() — 列表长度
print(len(fruits)) # 5
# count() — 统计出现次数
print(fruits.count("香蕉")) # 2
print(fruits.count("西瓜")) # 0(不存在返回0,不会报错)
# index() — 查找第一个匹配的索引
print(fruits.index("橘子")) # 2
print(fruits.index("香蕉")) # 1(只返回第一个)
# in — 成员检查
print("苹果" in fruits) # True
print("西瓜" in fruits) # False
print("西瓜" not in fruits) # True
💡 性能提示:
in对列表是 O(n) 查找,元素多时较慢。如果需要频繁做成员检查,使用后面的集合 (Set) 会更高效。
八、排序
nums = [3, 1, 4, 1, 5, 9, 2, 6]
# sorted() — 返回新列表,不修改原列表
asc = sorted(nums)
desc = sorted(nums, reverse=True)
print(asc) # [1, 1, 2, 3, 4, 5, 6, 9]
print(desc) # [9, 6, 5, 4, 3, 2, 1, 1]
# sort() — 原地排序,修改原列表
nums.sort()
print(nums) # [1, 1, 2, 3, 4, 5, 6, 9]
# 字符串排序
words = ["banana", "Apple", "cherry", "apple"]
words.sort() # 默认:大写优先
print(words) # ['Apple', 'apple', 'banana', 'cherry']
words.sort(key=str.lower) # 不区分大小写
print(words) # ['Apple', 'apple', 'banana', 'cherry']
按自定义规则排序——这是一个非常有用的技巧:
# 按字符串长度排序
words = ["python", "go", "c", "javascript", "rust"]
words.sort(key=len)
print(words) # ['c', 'go', 'rust', 'python', 'javascript']
# 按元组中第二个元素排序(回顾上一章的元组知识)
students = [("小明", 85), ("小红", 92), ("小刚", 78)]
students.sort(key=lambda s: s[1]) # 按分数排序
print(students) # [('小刚', 78), ('小明', 85), ('小红', 92)]
九、复制列表
这是一个初学者 最常见的陷阱:
a = [1, 2, 3]
# ❌ 错误方式:这不是复制,是指向同一个列表!
b = a
b[0] = 999
print(a) # [999, 2, 3] — a 也被改了!
# ✅ 正确复制方式
a = [1, 2, 3]
b = a.copy() # 方法1:copy()
c = list(a) # 方法2:构造函数
d = a[:] # 方法3:切片
e = a + [] # 方法4:拼接空列表
b[0] = 999
print(a) # [1, 2, 3] — 原列表不受影响
print(b) # [999, 2, 3]
⚠️ 注意:以上都是浅拷贝。如果列表中包含嵌套列表,内部列表仍然共享:
nested = [[1, 2], [3, 4]]
shallow = nested.copy()
shallow[0][0] = 999
print(nested[0]) # [999, 2] — 内部列表被修改了!
# 深拷贝需要 import copy
import copy
deep = copy.deepcopy(nested)
deep[0][0] = 1
print(nested[0]) # [999, 2] — 原列表不受影响
十、列表推导式
一行代码代替多行循环,Python 最优雅的特性之一:
# 基本形式
squares = [x**2 for x in range(1, 6)]
print(squares) # [1, 4, 9, 16, 25]
# 带条件的推导式
evens = [x for x in range(20) if x % 2 == 0]
print(evens) # [0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
# 多层循环(了解即可)
pairs = [(x, y) for x in range(2) for y in range(3)]
print(pairs) # [(0,0), (0,1), (0,2), (1,0), (1,1), (1,2)]
# 嵌套 if-else(三元表达式在推导式中)
labels = ["偶数" if x % 2 == 0 else "奇数" for x in range(1, 6)]
print(labels) # ['奇数', '偶数', '奇数', '偶数', '奇数']
💡 性能提示:列表推导式比等价的
for+append快约 2-3 倍,代码也更简洁。
十一、遍历技巧
fruits = ["苹果", "香蕉", "橘子"]
# 方式1:直接遍历元素(最常用)
for fruit in fruits:
print(fruit)
# 方式2:需要索引时用 enumerate()
for i, fruit in enumerate(fruits):
print(f"{i}: {fruit}")
# 方式3:同时遍历多个列表用 zip()
names = ["小明", "小红", "小刚"]
scores = [85, 92, 78]
for name, score in zip(names, scores):
print(f"{name}: {score}分")
# 方式4:反向遍历
for fruit in reversed(fruits):
print(fruit)
十二、常用方法速查表
| 方法 | 用途 | 是否修改原列表 |
|---|---|---|
| `append(x)` | 末尾添加元素 | ✅ |
| `extend(iter)` | 合并列表 | ✅ |
| `insert(i, x)` | 在位置 i 插入 | ✅ |
| `remove(x)` | 删除第一个 x | ✅ |
| `pop(i)` | 删除位置 i 并返回 | ✅ |
| `clear()` | 清空 | ✅ |
| `index(x)` | 查找 x 的位置 | — |
| `count(x)` | 统计 x 出现次数 | — |
| `sort()` | 原地排序 | ✅ |
| `reverse()` | 原地反转 | ✅ |
| `copy()` | 浅拷贝 | — |
小结
- 列表用
[]创建,元素有序可重复,支持索引和切片 append加末尾,insert插指定位置,extend合并列表pop删索引,remove删值,clear清空,del删索引或切片a = b不是复制,用copy()或a[:]- 列表推导式让代码简洁高效,值得多用
- 排序用
sort()或sorted(),结合key参数可以自定义规则
小练习
- 创建一个包含数字 1 到 10 的列表,然后反转它
- 从列表
[3, 7, 1, 9, 2, 5]中找出最大值和最小值 - 用列表推导式生成 1 到 100 中所有能被 7 整除的数
- 把列表
["a", "b", "c"]和[1, 2, 3]组合成["a1", "b2", "c3"]
💬 下一章预告:学完列表后,下一章学习元组 (Tuple)——它和列表很像,但最大的区别是不可修改,这在某些场景下非常有用。