Python list常规用法与经典技巧
一、基础用法
1. 创建列表
lst = [1, 2, 3] # 字面量
lst = [] # 空列表
lst = list() # 空列表
lst = list("abc") # ['a', 'b', 'c']
lst = list(range(5)) # [0, 1, 2, 3, 4]
lst = [0] * 5 # [0, 0, 0, 0, 0]
lst = [i for i in range(5)] # [0, 1, 2, 3, 4]
2. 访问元素
lst = [10, 20, 30, 40, 50]
lst[0] # 10,第一个
lst[-1] # 50,最后一个
lst[1:3] # [20, 30],切片
lst[:2] # [10, 20],前两个
lst[2:] # [30, 40, 50],从第三个到末尾
lst[::2] # [10, 30, 50],步长 2
lst[::-1] # [50, 40, 30, 20, 10],反转
3. 增
lst = [1, 2, 3]
lst.append(4) # 尾部添加,[1,2,3,4]
lst.insert(0, 0) # 指定位置插入,[0,1,2,3,4]
lst.extend([5, 6]) # 批量添加,[0,1,2,3,4,5,6]
lst += [7] # 等价于 extend,[0,1,2,3,4,5,6,7]
append vs extend:
lst = [1, 2]
lst.append([3, 4]) # [1, 2, [3, 4]],把列表当整体
lst = [1, 2]
lst.extend([3, 4]) # [1, 2, 3, 4],拆开逐个加
4. 删
lst = [1, 2, 3, 4, 5]
lst.pop() # 删尾部,返回 5,lst = [1,2,3,4]
lst.pop(0) # 删指定位置,返回 1,lst = [2,3,4]
lst.remove(3) # 按值删第一个匹配项,lst = [2,4]
del lst[0] # 按索引删,lst = [4]
lst.clear() # 清空,lst = []
remove vs pop:
remove(value):按值删,不知道索引时用。pop(index):按索引删,返回被删的值。
5. 改
lst = [1, 2, 3, 4, 5]
lst[0] = 100 # [100, 2, 3, 4, 5]
lst[1:3] = [20, 30] # 切片赋值,[100, 20, 30, 4, 5]
lst[1:3] = [1, 2, 3] # 长度可以变,[100, 1, 2, 3, 4, 5]
6. 查
lst = [10, 20, 30, 20]
lst[0] # 按索引,10
lst.index(20) # 按值找索引,1(第一个匹配)
lst.count(20) # 统计出现次数,2
20 in lst # 成员判断,True
len(lst) # 长度,4
7. 排序与反转
lst = [3, 1, 4, 1, 5]
lst.sort() # 原地排序,[1, 1, 3, 4, 5]
lst.sort(reverse=True) # 降序,[5, 4, 3, 1, 1]
lst.sort(key=len) # 按自定义规则
lst.reverse() # 原地反转
sorted(lst) # 返回新列表,不改原列表
sorted(lst, reverse=True) # 降序
sorted(lst, key=lambda x: -x) # 按自定义规则
sort vs sorted:
lst.sort():原地排序,返回None,改原列表。sorted(lst):返回新列表,原列表不变。
二、经典用法
1. 列表推导式
# 平方
squares = [x**2 for x in range(5)] # [0, 1, 4, 9, 16]
# 筛选偶数
evens = [x for x in range(10) if x % 2 == 0] # [0, 2, 4, 6, 8]
# 转换 + 筛选
strs = ["1", "-2", "3"]
positives = [int(s) for s in strs if int(s) > 0] # [1, 3]
# 嵌套
pairs = [(x, y) for x in [1, 2] for y in ["a", "b"]]
# [(1, 'a'), (1, 'b'), (2, 'a'), (2, 'b')]
2. 遍历时带索引:enumerate
fruits = ["apple", "banana", "cherry"]
for i, fruit in enumerate(fruits):
print(i, fruit)
# 0 apple
# 1 banana
# 2 cherry
# 从 1 开始
for i, fruit in enumerate(fruits, start=1):
print(i, fruit)
3. 同时遍历多个列表:zip
names = ["小明", "小红", "小刚"]
ages = [25, 30, 28]
for name, age in zip(names, ages):
print(name, age)
# 转成列表
pairs = list(zip(names, ages))
# [('小明', 25), ('小红', 30), ('小刚', 28)]
# 解压
names, ages = zip(*pairs)
4. 扁平化嵌套列表
nested = [[1, 2], [3, 4], [5, 6]]
# 方法一:列表推导式
flat = [x for sublist in nested for x in sublist]
# [1, 2, 3, 4, 5, 6]
# 方法二:itertools.chain
import itertools
flat = list(itertools.chain(*nested))
5. 去重且保持顺序
lst = [3, 1, 2, 3, 1, 4]
# 方法一:dict.fromkeys(推荐)
unique = list(dict.fromkeys(lst))
# [3, 1, 2, 4]
# 方法二:set(不保持顺序)
unique = list(set(lst))
# 顺序可能变
6. 列表转字符串
words = ["hello", "world", "python"]
# 用空格连接
s = " ".join(words) # "hello world python"
# 用逗号连接
s = ",".join(words) # "hello,world,python"
# 注意:join 只能连接字符串列表
nums = [1, 2, 3]
s = ",".join(map(str, nums)) # "1,2,3"
7. 字符串转列表
s = "hello world"
lst = s.split() # ['hello', 'world']
lst = list(s) # ['h', 'e', 'l', 'l', 'o', ' ', 'w', ...]
lst = s.split(",") # 按逗号切
8. 切片赋值与删除
lst = [1, 2, 3, 4, 5]
lst[1:3] = [10, 20] # [1, 10, 20, 4, 5]
lst[1:3] = [] # 删除切片,[1, 4, 5]
del lst[1:3] # 删除切片
lst[:] = [1, 2, 3] # 替换整个列表内容
9. 复制列表
lst = [1, 2, 3]
# 浅拷贝
b = lst.copy() # [1, 2, 3]
b = lst[:] # [1, 2, 3]
b = list(lst) # [1, 2, 3]
# 注意:= 不是复制,是引用
c = lst # c 和 lst 是同一个列表
c.append(4)
print(lst) # [1, 2, 3, 4],lst 也被改了
浅拷贝 vs 深拷贝:
import copy
nested = [[1, 2], [3, 4]]
shallow = copy.copy(nested) # 浅拷贝,内层还是共享
deep = copy.deepcopy(nested) # 深拷贝,完全独立
shallow[0].append(99)
print(nested) # [[1, 2, 99], [3, 4]],被影响
deep[0].append(100)
print(nested) # [[1, 2, 99], [3, 4]],不受影响
10. 条件筛选与转换:filter 和 map
nums = [1, 2, 3, 4, 5]
# filter:筛选
evens = list(filter(lambda x: x % 2 == 0, nums))
# [2, 4]
# map:转换
squares = list(map(lambda x: x**2, nums))
# [1, 4, 9, 16, 25]
# 更推荐列表推导式
evens = [x for x in nums if x % 2 == 0]
squares = [x**2 for x in nums]
11. 列表作为栈和队列
栈(后进先出):
stack = []
stack.append(1) # 入栈
stack.append(2)
stack.append(3)
print(stack.pop()) # 3,出栈
print(stack.pop()) # 2
队列(先进先出):
from collections import deque
queue = deque()
queue.append(1) # 入队
queue.append(2)
queue.append(3)
print(queue.popleft()) # 1,出队
print(queue.popleft()) # 2
不要用 list 做队列,因为 pop(0) 是 O(n):
queue = [1, 2, 3]
queue.pop(0) # O(n),效率低
12. 二维列表(矩阵)
# 创建 3x3 矩阵
matrix = [[0] * 3 for _ in range(3)]
# [[0, 0, 0], [0, 0, 0], [0, 0, 0]]
# 访问
matrix[0][1] = 5
# [[0, 5, 0], [0, 0, 0], [0, 0, 0]]
# 转置
transposed = [[row[i] for row in matrix] for i in range(3)]
# 遍历
for row in matrix:
for val in row:
print(val)
经典坑:不要用 [[0] * 3] * 3 创建二维列表。
matrix = [[0] * 3] * 3
matrix[0][0] = 1
print(matrix) # [[1, 0, 0], [1, 0, 0], [1, 0, 0]],三行共享同一个列表!
13. 列表作为函数参数
def add_item(lst, item):
lst.append(item)
nums = [1, 2]
add_item(nums, 3)
print(nums) # [1, 2, 3],原列表被修改
# 不想改原列表,传副本
add_item(nums[:], 4)
print(nums) # [1, 2, 3],没变
经典坑:默认参数用可变对象。
def add_item(item, lst=[]): # ❌
lst.append(item)
return lst
print(add_item(1)) # [1]
print(add_item(2)) # [1, 2],默认列表被共享了
正确写法:
def add_item(item, lst=None):
if lst is None:
lst = []
lst.append(item)
return lst
14. 列表排序的高级用法
# 按绝对值排序
nums = [-3, 1, -2, 4]
nums.sort(key=abs) # [1, -2, -3, 4]
# 按字符串长度排序
words = ["apple", "hi", "banana"]
words.sort(key=len) # ['hi', 'apple', 'banana']
# 按多个条件排序
students = [("小明", 25), ("小红", 20), ("小刚", 25)]
students.sort(key=lambda x: (x[1], x[0])) # 先按年龄,再按名字
# 稳定排序
# Python 的 sort 是稳定的,相同 key 的元素保持原顺序
15. 列表的成员判断
lst = [1, 2, 3, 4, 5]
print(3 in lst) # True
print(10 not in lst) # True
# 列表的 in 是 O(n),集合的 in 是 O(1)
# 频繁成员判断,先转 set
s = set(lst)
print(3 in s) # O(1)
16. 列表的统计
lst = [1, 2, 2, 3, 3, 3]
print(len(lst)) # 6,长度
print(sum(lst)) # 14,求和
print(max(lst)) # 3,最大值
print(min(lst)) # 1,最小值
print(lst.count(3)) # 3,统计出现次数
# 平均值
avg = sum(lst) / len(lst)
17. 列表解包
# 基本解包
a, b, c = [1, 2, 3]
# 星号解包
first, *rest = [1, 2, 3, 4, 5]
# first = 1, rest = [2, 3, 4, 5]
*init, last = [1, 2, 3, 4, 5]
# init = [1, 2, 3, 4], last = 5
a, *mid, b = [1, 2, 3, 4, 5]
# a = 1, mid = [2, 3, 4], b = 5
18. 合并列表
a = [1, 2]
b = [3, 4]
# 方法一:+
c = a + b # [1, 2, 3, 4],新列表
# 方法二:extend
a.extend(b) # a 变成 [1, 2, 3, 4]
# 方法三:解包
c = [*a, *b] # [1, 2, 3, 4]
# 方法四:itertools.chain
import itertools
c = list(itertools.chain(a, b))
19. 列表的 * 重复
[0] * 5 # [0, 0, 0, 0, 0]
[1, 2] * 3 # [1, 2, 1, 2, 1, 2]
经典坑:嵌套列表用 * 会共享引用。
matrix = [[0] * 3] * 3 # ❌ 三行是同一个列表
matrix[0][0] = 1
print(matrix) # [[1, 0, 0], [1, 0, 0], [1, 0, 0]]
20. 列表推导式 + 条件表达式
# 偶数取平方,奇数取相反数
nums = [1, 2, 3, 4, 5]
result = [x**2 if x % 2 == 0 else -x for x in nums]
# [-1, 4, -3, 16, -5]
三、常见坑总结
| 坑 | 说明 | 正确做法 |
|---|---|---|
| 遍历时删元素 | 会跳过元素 | 遍历副本 lst[:] 或用推导式 |
[[0]*3]*3 创建二维 | 三行共享引用 | [[0]*3 for _ in range(3)] |
默认参数用 [] | 被所有调用共享 | 用 None 做默认值 |
b = a 以为是复制 | 只是引用 | 用 a.copy() 或 a[:] |
sort() 返回 None | 以为返回新列表 | 用 sorted() 或直接 lst.sort() |
| 浅拷贝嵌套列表 | 内层还是共享 | 用 copy.deepcopy() |
| 列表做队列 | pop(0) 是 O(n) | 用 collections.deque |
频繁 in 判断 | 列表是 O(n) | 转 set |
四、一句话总结
| 用法 | 写法 |
|---|---|
| 创建 | [1,2,3]、list(range(5))、[x for x in ...] |
| 增 | append、insert、extend |
| 删 | pop、remove、del、clear |
| 改 | lst[i] = x、切片赋值 |
| 查 | 索引、index、count、in |
| 排序 | sort() 原地、sorted() 新列表 |
| 遍历带索引 | enumerate |
| 同时遍历多个 | zip |
| 去重保序 | list(dict.fromkeys(lst)) |
| 扁平化 | [x for sub in nested for x in sub] |
| 栈 | append + pop |
| 队列 | collections.deque |
| 复制 | copy()、[:]、deepcopy() |
| 拼接 | +、extend、[*a, *b] |
| 解包 | a, *rest = lst |
核心记住:list 是可变有序序列,增删改查是基础,列表推导式、enumerate、zip、dict.fromkeys 是经典。避开遍历时修改、二维列表共享引用、默认参数可变对象这几个大坑。