云计算百科
云计算领域专业知识百科平台

对python的再认识-基于数据结构进行-a002-列表-列表推导式

Python 列表推导式-与list()拓展

本文聚焦 Python 列表推导式(List Comprehension)的完整用法,包含基础语法、高级技巧、与 list() 的对比及最佳实践。

我也将给出个人思维导图

在这里插入图片描述


一、基础语法

1.1 基本形式

列表推导式用一行代码替代传统的 for 循环,语法结构为:

[表达式 for 变量 in 可迭代对象]

示例对比:

# 传统写法
squares = []
for x in range(5):
squares.append(x ** 2)

# 列表推导式
squares = [x ** 2 for x in range(5)]
# 结果: [0, 1, 4, 9, 16]

1.2 带条件的推导式

添加 if 子句进行过滤:

# 只保留偶数
evens = [x for x in range(10) if x % 2 == 0]
# 结果: [0, 2, 4, 6, 8]

# 过滤字符串
words = ['hello', 'world', 'python', 'hi']
long_words = [w for w in words if len(w) > 3]
# 结果: ['hello', 'world', 'python']

# 多条件过滤
nums = [1, 2, 3, 4, 5, 6]
result = [x for x in nums if x > 2 and x < 6]
# 结果: [3, 4, 5]

注意:条件 if 放在 for 之后,只用于过滤,不用于分支选择。

1.3 带分支的推导式

使用 if-else 三元表达式进行分支选择:

# 根据条件返回不同值
result = ['偶数' if x % 2 == 0 else '奇数' for x in range(5)]
# 结果: ['偶数', '奇数', '偶数', '奇数', '偶数']

# 数值转换
nums = [1, 2, 3, 4, 5]
abs_nums = [x if x >= 0 else x for x in nums]
# 结果: [1, 2, 3, 4, 5]

# 复杂分支
scores = [85, 92, 78, 65, 95]
grades = ['A' if s >= 90 else 'B' if s >= 80 else 'C' for s in scores]
# 结果: ['B', 'A', 'C', 'C', 'A']

注意:if-else 放在 for 之前,用于表达式的分支选择。


二、高级用法

2.1 双重循环

处理嵌套可迭代对象:

# 生成所有坐标组合
coords = [(x, y) for x in range(3) for y in range(2)]
# 结果: [(0, 0), (0, 1), (1, 0), (1, 1), (2, 0), (2, 1)]

# 等价于:
coords = []
for x in range(3):
for y in range(2):
coords.append((x, y))

# 双重循环带条件
pairs = [(x, y) for x in range(3) for y in range(3) if x != y]
# 结果: [(0, 1), (0, 2), (1, 0), (1, 2), (2, 0), (2, 1)]

2.2 嵌套列表扁平化

将二维列表展开为一维:

matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]

# 扁平化
flat = [num for row in matrix for num in row]
# 结果: [1, 2, 3, 4, 5, 6, 7, 8, 9]

# 等价于:
flat = []
for row in matrix:
for num in row:
flat.append(num)

# 带条件过滤
even_flat = [num for row in matrix for num in row if num % 2 == 0]
# 结果: [2, 4, 6, 8]

注意:循环顺序与书写顺序一致,外层循环在前,内层循环在后。

2.3 结合函数调用

在表达式中调用函数:

# 字符串处理
names = ['alice', 'bob', 'charlie']
capitalized = [name.title() for name in names]
# 结果: ['Alice', 'Bob', 'Charlie']

# 数学运算
import math
rounded = [round(math.sqrt(x), 2) for x in range(1, 6)]
# 结果: [1.0, 1.41, 1.73, 2.0, 2.24]

# 自定义函数
def process(x):
return x * 2 + 1

result = [process(x) for x in range(5)]
# 结果: [1, 3, 5, 7, 9]

2.4 与 enumerate/range 组合

# 带索引的推导式
words = ['apple', 'banana', 'cherry']
indexed = [f"{i}: {w}" for i, w in enumerate(words)]
# 结果: ['0: apple', '1: banana', '2: cherry']

# 带索引的条件
indexed_even = [w for i, w in enumerate(words) if i % 2 == 0]
# 结果: ['apple', 'cherry']

# 步长范围
evens = [x for x in range(0, 10, 2)]
# 结果: [0, 2, 4, 6, 8]


三、与 list() 构造函数对比

3.1 list() 基础用法

list() 是列表的构造函数,用于创建列表:

# 创建空列表
empty = list()
# 等同于: empty = []

# 从可迭代对象创建
nums = list(range(5))
# 结果: [0, 1, 2, 3, 4]

# 从字符串创建
chars = list('hello')
# 结果: ['h', 'e', 'l', 'l', 'o']

# 从元组创建
tup = (1, 2, 3)
lst = list(tup)
# 结果: [1, 2, 3]

3.2 list() 转换场景

list() 主要用于类型转换:

# 字典转列表(只保留键)
d = {'a': 1, 'b': 2}
keys = list(d)
# 结果: ['a', 'b']

# 字典 items() 转列表
items = list(d.items())
# 结果: [('a', 1), ('b', 2)]

# 集合转列表
s = {1, 2, 3}
lst = list(s)
# 结果: [1, 2, 3](顺序可能不同)

# 迭代器转列表
it = iter([1, 2, 3])
lst = list(it)
# 结果: [1, 2, 3]

3.3 列表推导式 vs list() + map

# 使用 list() + map
nums = [1, 2, 3, 4]
squares = list(map(lambda x: x ** 2, nums))
# 结果: [1, 4, 9, 16]

# 使用列表推导式(更清晰)
squares = [x ** 2 for x in nums]
# 结果: [1, 4, 9, 16]

# 带条件的过滤
# map 需要配合 filter
evens_squared = list(map(lambda x: x ** 2, filter(lambda x: x % 2 == 0, nums)))

# 列表推导式(更简洁)
evens_squared = [x ** 2 for x in nums if x % 2 == 0]


四、性能对比

4.1 速度测试

import timeit

# 测试代码:生成 0-999999 的平方
TEST_COMP = "[x ** 2 for x in range(1000000)]"
TEST_FOR = """
result = []
for x in range(1000000):
result.append(x ** 2)
"""

TEST_MAP = "list(map(lambda x: x ** 2, range(1000000)))"

方法相对速度说明
列表推导式 1.0x 基准,最快
map + lambda 1.3x 略慢,lambda 有开销
传统 for 循环 1.5x append 调用有额外开销

4.2 性能优势原因

  • 字节码优化:列表推导式使用专用字节码指令 LIST_APPEND
  • 减少方法查找:避免 append 方法每次调用时的查找
  • C 层执行:部分循环逻辑在 C 层高效执行

4.3 内存对比

# 列表推导式 – 立即创建完整列表
lst = [x ** 2 for x in range(1000000)] # 占用 ~8MB 内存

# list() + map – 同样创建完整列表
lst = list(map(lambda x: x ** 2, range(1000000))) # 占用 ~8MB 内存

# 生成器表达式 – 惰性计算(注意是圆括号)
gen = (x ** 2 for x in range(1000000)) # 几乎不占用内存
sum(gen) # 需要时才计算

注意:生成器表达式 (x for x in …) 不是列表推导式,它返回生成器对象而非列表。


五、最佳实践

5.1 何时使用列表推导式

推荐场景:

# 简单转换
doubled = [x * 2 for x in range(10)]

# 简单过滤
positives = [x for x in nums if x > 0]

# 组合操作
result = [x.title() for x in names if len(x) > 3]

# 提取属性
ages = [person.age for person in people]

5.2 何时不使用

不推荐场景:

# 过于复杂 – 可读性差
# 不推荐
bad = [(x, y, x*y) for x in range(10) for y in range(10) if x != y if x * y > 10]

# 推荐 – 使用传统循环
good = []
for x in range(10):
for y in range(10):
if x != y and x * y > 10:
good.append((x, y, x * y))

# 多重嵌套分支
# 不推荐
bad = [x ** 2 if x % 2 == 0 else x ** 3 if x < 5 else x for x in range(10)]

# 推荐
good = []
for x in range(10):
if x % 2 == 0:
good.append(x ** 2)
elif x < 5:
good.append(x ** 3)
else:
good.append(x)

5.3 代码风格建议

原则好的示例不好的示例
保持简短 [x*2 for x in nums] [very_long_expression for x in nums]
避免嵌套过深 单层或双层循环 三层及以上循环
有意义的变量名 [s.title() for s in names] [i for i in j]
优先可读性 复杂逻辑用传统循环 强行用推导式

六、常见陷阱

6.1 副作用

# 不推荐:推导式只用于创建列表,不应有副作用
results = [print(x) for x in range(5)]
# 结果: [None, None, None, None, None] – 打印了 5 次

# 推荐:分离逻辑
for x in range(5):
print(x)
results = [x for x in range(5)]

6.2 可变对象引用

# 错误:创建多个引用同一列表
matrix = [[0] * 3] * 3
matrix[0][1] = 5
# matrix: [[0, 5, 0], [0, 5, 0], [0, 5, 0]] – 所有行都被修改

# 正确:每行是独立列表
matrix = [[0] * 3 for _ in range(3)]
matrix[0][1] = 5
# matrix: [[0, 5, 0], [0, 0, 0], [0, 0, 0]] – 只修改第一行

6.3 混淆 if 位置

# if 在 for 之后:过滤
[x for x in range(10) if x % 2 == 0] # [0, 2, 4, 6, 8]

# if-else 在 for 之前:分支
[x if x % 2 == 0 else 1 for x in range(5)] # [0, -1, 2, -1, 4]

# 常见错误:把过滤 if 放在前面
# [x if x % 2 == 0 for x in range(10)] # SyntaxError


七、总结

方面要点
核心语法 [表达式 for 变量 in 可迭代对象 if 条件]
if 位置 过滤用 for … if,分支用 … if … else … for
优势 简洁、快速、可读性强
局限 复杂逻辑降低可读性
最佳实践 简单操作用推导式,复杂逻辑用循环
vs list() list() 用于类型转换,推导式用于生成新列表
赞(0)
未经允许不得转载:网硕互联帮助中心 » 对python的再认识-基于数据结构进行-a002-列表-列表推导式
分享到: 更多 (0)

评论 抢沙发

评论前必须登录!