飞翔飞翔
主页
  • 计算机基础

    • TCP/IP协议
    • Linux命令
  • 数据库

    • SQL教程
  • 编程语言

    • C语言
    • Python2
    • Python3
  • 数据格式

    • JSON教程
  • 工具

    • Markdown指南
  • Git

    • GitFlow
  • Quartz

    • Quartz教程
  • Java

    • Java设计模式
  • 缓存

    • Redis教程
联系
阿里云
主页
  • 计算机基础

    • TCP/IP协议
    • Linux命令
  • 数据库

    • SQL教程
  • 编程语言

    • C语言
    • Python2
    • Python3
  • 数据格式

    • JSON教程
  • 工具

    • Markdown指南
  • Git

    • GitFlow
  • Quartz

    • Quartz教程
  • Java

    • Java设计模式
  • 缓存

    • Redis教程
联系
阿里云
  • 学习路径
  • 第1章 Python简介

    • Python是什么
    • 安装与运行
    • 交互式解释器
    • 注释与编码规范
  • 第2章 变量与数据类型

    • 变量与对象
    • 整数 int
    • 浮点数 float
    • 复数 complex
    • 布尔值 bool
    • 字符串 str
    • 空值 None
    • 类型转换
  • 第3章 运算符与表达式

    • 算术运算符
    • 比较运算符
    • 赋值运算符
    • 逻辑运算符
    • 位运算符
    • 身份与成员运算符
    • 海象运算符
    • 运算符优先级
  • 第4章 流程控制

    • if 语句
    • if-else 语句
    • if-elif-else 语句
    • match-case 语句
    • 条件表达式(三元运算符)
    • while 循环
    • for 循环
    • range 函数
    • break 与 continue
    • 循环的 else 子句
    • pass 语句
  • 第5章 数据结构

    • 列表创建与索引
    • 列表方法
    • 列表推导式
    • 元组
    • 序列解包
    • 集合
    • 字典创建与访问
    • 字典方法
    • 字典推导式
    • range 对象
  • 第6章 函数

    • 定义函数
    • 位置参数与关键字参数
    • 默认参数
    • 可变参数
    • 解包实参
    • 函数返回值
    • lambda 表达式
    • 文档字符串与注解
    • 作用域与命名空间
    • global 与 nonlocal
  • 第7章 模块与包

    • 模块导入
    • 模块搜索路径
    • 包与相对导入
    • 标准库概览
  • 第8章 文件与输入输出

    • 文件读写
    • 上下文管理器
    • 字符串格式化
    • JSON 与 CSV
  • 第9章 面向对象

    • 类与对象
    • 方法
    • 实例变量与类变量
    • 私有变量
    • 继承
    • 多重继承
    • 魔术方法
    • 属性装饰器
    • 数据类 dataclass
  • 第10章 异常处理

    • 语法错误与异常
    • try-except
    • 异常链与 raise
    • 清理操作
    • 自定义异常
  • 第11章 迭代器与生成器

    • 迭代器协议
    • 生成器
    • 生成器表达式
    • 迭代工具
  • 第12章 高级特性

    • 装饰器
    • 函数式编程
  • 第13章 工程实践

    • 测试与调试
    • 代码质量
    • 虚拟环境

列表推导式

列表推导式(list comprehension)提供了一种简洁、可读的方式来创建列表,将循环和条件判断压缩到一行表达式中。相比等价的 for 循环,推导式通常执行更快,因为它在 C 层面完成迭代。

基本语法

最简形式为 [expression for item in iterable],对可迭代对象中的每个元素求值表达式,收集结果组成新列表:

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

# 推导式写法
squares = [x ** 2 for x in range(10)]
# [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

表达式可以是任意合法 Python 表达式,包括函数调用、方法调用和复杂运算:

from math import pi

# 函数调用
[str(round(pi, i)) for i in range(1, 6)]
# ['3.1', '3.14', '3.142', '3.1416', '3.14159']

# 方法调用
fresh = ['  banana', '  loganberry ', 'passion fruit  ']
[fruit.strip() for fruit in fresh]
# ['banana', 'loganberry', 'passion fruit']

# 创建元组(必须加括号)
[(x, x ** 2) for x in range(6)]
# [(0, 0), (1, 1), (2, 4), (3, 9), (4, 16), (5, 25)]

注意:当表达式是元组时,圆括号不可省略。[x, x**2 for x in range(6)] 会触发 SyntaxError,因为逗号会被解析为列表分隔符而非元组构造符。

带 if 过滤

在 for 子句后添加 if condition,可以筛选满足条件的元素:

vec = [-4, -2, 0, 2, 4]

# 过滤负数,只保留非负
[x for x in vec if x >= 0]   # [0, 2, 4]

# 过滤后转换
[abs(x) for x in vec if x < 0]  # [4, 2]

if 子句在表达式求值之前执行。多个条件可以链式书写:

nums = range(20)
[x for x in nums if x % 2 == 0 if x % 3 == 0]  # [0, 6, 12, 18]
# 等价于 if x % 2 == 0 and x % 3 == 0

多重 for 子句

列表推导式支持多个 for 子句,实现嵌套循环的效果。执行顺序与嵌套 for 循环一致,从左到右依次嵌套:

# 嵌套循环的等价写法
result = []
for x in [1, 2, 3]:
    for y in [3, 1, 4]:
        if x != y:
            result.append((x, y))

# 推导式写法
[(x, y) for x in [1, 2, 3] for y in [3, 1, 4] if x != y]
# [(1, 3), (1, 4), (2, 3), (2, 1), (2, 4), (3, 1), (3, 4)]

多重 for 常用于展平嵌套列表:

matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
[num for row in matrix for num in row]
# [1, 2, 3, 4, 5, 6, 7, 8, 9]

推导式中 for 的顺序必须与等价嵌套循环完全一致,否则逻辑和结果都会改变。

嵌套推导式

推导式的表达式部分本身可以是另一个列表推导式,常用于处理多维数据:

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

# 转置矩阵
[[row[i] for row in matrix] for i in range(4)]
# [[1, 5, 9], [2, 6, 10], [3, 7, 11], [4, 8, 12]]

嵌套推导式的执行顺序需要仔细理解:外层 for i in range(4) 控制内层推导式的执行次数,每次执行时内层独立求值。实际应用中,矩阵转置更推荐 zip(*matrix):

list(zip(*matrix))
# [(1, 5, 9), (2, 6, 10), (3, 7, 11), (4, 8, 12)]

与 map/filter 对比

在 Python 3 中,列表推导式在大多数情况下已取代 map() 和 filter():

# map 写法
squares = list(map(lambda x: x ** 2, range(10)))

# 推导式写法
squares = [x ** 2 for x in range(10)]

推导式可读性更强,且天然支持过滤和嵌套。map 配合 filter 需要嵌套调用,可读性急剧下降:

# map + filter 嵌套
list(map(lambda x: x ** 2, filter(lambda x: x > 0, vec)))

# 推导式一行搞定
[x ** 2 for x in vec if x > 0]

不过,当映射函数已经存在且无需 lambda 时,map 依然简洁:list(map(str, nums)) 与 [str(x) for x in nums] 各有千秋。

注意事项

Python 3 中,列表推导式拥有自己独立的局部作用域,循环变量不会泄漏到外部:

x = 'before'
[x ** 2 for x in range(3)]
print(x)   # 'before',x 未被覆盖

推导式虽好,但不宜过度嵌套。超过两层嵌套的推导式会严重损害可读性,此时应改用普通循环或提取为函数。

上一页
列表方法
下一页
元组