Python 列表推导式与生成器表达式

Python 列表推导式与生成器表达式

在 Python 中,列表推导式(List Comprehension)和生成器表达式(Generator Expression)是处理序列数据的高效工具。它们不仅能简化代码,还能提升数据处理的效率。本文将详细介绍这两种表达式的语法、特性、区别及适用场景,并通过丰富的实例帮助你掌握它们的使用技巧。

一、列表推导式:简洁高效的列表创建

列表推导式是 Python 中创建列表的一种简洁语法,它将循环、条件判断等逻辑浓缩成一行代码,既直观又高效。

1. 基本语法

​# 基本格式
[表达式 for 变量 in 可迭代对象]# 带条件判断的格式
[表达式 for 变量 in 可迭代对象 if 条件]

示例 1:创建简单列表

​# 传统方式:使用for循环创建列表
squares = []
for i in range(10):squares.append(i **2)
print(squares)  # [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]# 列表推导式:一行代码完成
squares = [i** 2 for i in range(10)]
print(squares)  # 结果同上

示例 2:带条件过滤的列表推导式

​# 筛选偶数的平方
even_squares = [i **2 for i in range(10) if i % 2 == 0]
print(even_squares)  # [0, 4, 16, 36, 64]# 字符串处理:提取单词首字母大写
words = ["apple", "banana", "cherry", "date"]
capitalized = [word.capitalize() for word in words if len(word) > 5]
print(capitalized)  # ['Banana', 'Cherry']

2. 嵌套列表推导式

列表推导式支持嵌套,可用于处理二维数据结构(如矩阵):

​# 二维列表(矩阵)
matrix = [[1, 2, 3],[4, 5, 6],[7, 8, 9]
]# 提取矩阵对角线元素
diagonal = [matrix[i][i] for i in range(len(matrix))]
print(diagonal)  # [1, 5, 9]# 矩阵转置(行变列)
transposed = [[row[i] for row in matrix] for i in range(3)]
print(transposed)  # [[1, 4, 7], [2, 5, 8], [3, 6, 9]]# 扁平化矩阵(二维转一维)
flattened = [num for row in matrix for num in row]
print(flattened)  # [1, 2, 3, 4, 5, 6, 7, 8, 9]

3. 列表推导式的优势

  • 简洁性:将多行循环逻辑压缩为一行,代码更紧凑
  • 可读性:符合 “声明式编程” 风格,直接表达 “要什么” 而非 “怎么做”
  • 性能:通常比等效的for循环 +append()更快(内部优化)
  • 功能性:结合条件判断可实现复杂过滤逻辑

4. 常见误区与最佳实践

  • 避免过度复杂:嵌套层级不宜过多(建议不超过 2 层),否则可读性下降

  • ​# 不推荐:过于复杂的嵌套
    complex = [x for x in [y for y in range(20) if y % 2 == 0] if x % 4 == 0]# 推荐:拆分逻辑
    even_numbers = [y for y in range(20) if y % 2 == 0]
    divisible_by_4 = [x for x in even_numbers if x % 4 == 0]

    注意变量泄漏:Python 3 中列表推导式的变量不会泄漏到外部作用域

​x = 10
[x for x in range(5)]
print(x)  # 输出10(变量x未被修改)

二、生成器表达式:惰性计算的内存优化方案

生成器表达式是一种创建生成器(Generator)的简洁语法,它与列表推导式类似,但采用惰性计算(Lazy Evaluation)策略,更适合处理大数据集。

1. 基本语法

​# 基本格式(注意使用圆括号)
(表达式 for 变量 in 可迭代对象)# 带条件判断的格式
(表达式 for 变量 in 可迭代对象 if 条件)

示例 1:创建生成器

​# 生成器表达式(圆括号可省略,视上下文而定)
squares_gen = (i **2 for i in range(10))
print(squares_gen)  # <generator object <genexpr> at 0x...># 遍历生成器(每次迭代才计算下一个值)
for num in squares_gen:print(num, end=" ")  # 0 1 4 9 16 25 36 49 64 81

示例 2:与列表推导式的直观对比

​# 列表推导式:立即生成所有元素并占用内存
list_comp = [i** 2 for i in range(1000000)]
print(type(list_comp))  # <class 'list'>
print(len(list_comp))   # 1000000(已全部生成)# 生成器表达式:仅在迭代时生成元素,内存占用极低
gen_expr = (i **2 for i in range(1000000))
print(type(gen_expr))   # <class 'generator'>
# print(len(gen_expr))  # 报错:生成器没有长度(元素未生成)

2. 核心特性:惰性计算

生成器表达式的核心优势在于惰性计算

  • 元素仅在被请求时(如next()调用或for循环迭代)才会计算
  • 计算后的值不会被存储,迭代结束后无法重新访问(一次性使用)
  • 内存占用固定(与数据规模无关),适合处理超大数据集或无限序列
​# 处理无限序列(列表推导式会直接崩溃)
def infinite_numbers():n = 0while True:yield nn += 1# 生成器表达式筛选偶数
even_infinite = (x for x in infinite_numbers() if x % 2 == 0)# 安全获取前5个偶数(不会耗尽内存)
for _ in range(5):print(next(even_infinite), end=" ")  # 0 2 4 6 8

3. 适用场景

  • 大数据处理:当数据量超过内存限制时,生成器表达式可逐批处理

  • ​# 处理大文件(无需一次性加载全部内容)
    def process_large_file(file_path):with open(file_path, "r") as f:# 生成器表达式逐行处理lines = (line.strip() for line in f)non_empty = (line for line in lines if line)  # 过滤空行for line in non_empty:# 处理逻辑(如数据分析、格式转换)pass

    链式处理:与其他迭代器函数(如mapfilter)配合,实现流式处理

  • ​# 生成器流水线
    numbers = range(100)
    squares = (x** 2 for x in numbers)
    even_squares = (x for x in squares if x % 2 == 0)
    sum_even = sum(even_squares)  # 按需计算,中间结果不存储

    节省内存:替代列表推导式处理临时数据(如仅需迭代一次的场景)

​# 计算1到100万的和(生成器表达式内存占用远低于列表)
total = sum(i for i in range(1000001))

4. 生成器表达式 vs 列表推导式:关键区别

特性列表推导式生成器表达式
语法标识方括号 []圆括号 ()(可省略)
返回类型列表 list生成器 generator
计算方式立即计算所有元素(贪婪计算)按需计算(惰性计算)
内存占用与数据规模成正比固定(极低)
可迭代次数多次(元素已存储)一次(元素计算后即丢弃)
支持的操作所有列表方法(lenindex等)仅迭代操作(nextfor循环)
适用场景小数据、需多次访问、随机访问大数据、单次迭代、内存受限场景

性能对比实验

​import memory_profiler
import time@memory_profiler.profile
def list_comprehension():return [i **2 for i in range(10** 7)]  # 1000万元素@memory_profiler.profile
def generator_expression():return sum(i **2 for i in range(10** 7))  # 同样1000万元素# 测试内存占用(列表推导式约占用380MB,生成器表达式约占用0.1MB)
list_comprehension()
generator_expression()# 测试时间(列表推导式耗时更长,因需先创建完整列表)
start = time.time()
list_comprehension()
print(f"列表推导式耗时:{time.time() - start:.2f}s")start = time.time()
generator_expression()
print(f"生成器表达式耗时:{time.time() - start:.2f}s")

三、实战应用:列表推导式与生成器表达式的协同使用

在实际开发中,两种表达式并非互斥关系,而是根据场景灵活选择:

1. 数据转换与过滤流水线

​# 1. 原始数据(可能很大)
data = range(1, 1000001)  # 1到100万# 2. 生成器表达式:筛选偶数(惰性计算)
even_numbers = (x for x in data if x % 2 == 0)# 3. 生成器表达式:计算平方(继续惰性计算)
even_squares = (x **2 for x in even_numbers)# 4. 列表推导式:取前100个结果(转为列表便于后续复用)
first_100 = [next(even_squares) for _ in range(100)]print(first_100[:5])  # [4, 16, 36, 64, 100]

2. 文本处理场景

​def process_text(file_path):# 生成器表达式:逐行读取并预处理with open(file_path, "r", encoding="utf-8") as f:lines = (line.strip() for line in f)non_empty = (line for line in lines if line)words = (word.lower() for line in non_empty for word in line.split())# 列表推导式:取前100个单词(小数据集)sample_words = [next(words) for _ in range(100)]print("样本单词:", sample_words[:10])# 生成器表达式:统计词频(大数据集)from collections import defaultdictfreq = defaultdict(int)for word in words:freq[word] += 1# 列表推导式:排序并返回前10高频词return sorted(freq.items(), key=lambda x: x[1], reverse=True)[:10]

3. 函数参数中的应用

许多内置函数(summaxminanyall等)接受可迭代对象作为参数,此时生成器表达式是更优选择:

​# 计算1到100的和(生成器表达式更省内存)
total = sum(i for i in range(1, 101))# 检查是否存在偶数(短路求值,找到第一个即停止)
has_even = any(i % 2 == 0 for i in [1, 3, 5, 7, 8, 9])# 找出最大平方数
max_square = max(x **2 for x in range(1, 10))

四、总结:如何选择合适的表达式?

1.当满足以下条件时,优先使用列表推导式

  • 数据规模较小(能完全放入内存)
  • 需要多次迭代或随机访问元素
  • 需要使用列表特有的方法(如appendsortreverse
  • 代码可读性要求高于内存优化

2.当满足以下条件时,优先使用生成器表达式

  • 处理大数据集(可能超出内存限制)
  • 只需迭代一次(如求和、过滤后立即处理)
  • 链式处理数据(与其他生成器或迭代器配合)
  • 内存资源受限,需要优化内存占用

3.通用原则

  • 从小数据开始,优先保证代码可读性
  • 当遇到内存问题或性能瓶颈时,考虑用生成器表达式重构
  • 复杂逻辑优先拆分,避免为了 “一行代码” 牺牲可读性

列表推导式和生成器表达式是 Python 中 “写得少,做得多” 的典型代表。掌握它们不仅能提升代码效率,更能体现 Pythonic 的编程风格 —— 简洁、优雅且高效。在实际开发中,灵活运用这两种工具,将使你的数据处理代码更上一层楼。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/bicheng/91017.shtml
繁体地址,请注明出处:http://hk.pswp.cn/bicheng/91017.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

XCF32PVOG48C Xilinx Platform Flash PROM

XCF32PVOG48C 是 Xilinx 公司推出的一款高容量、低功耗的 Platform Flash PROM&#xff08;平台闪存配置芯片&#xff09;&#xff0c;专为 Xilinx FPGA 和 CPLD 系列产品提供非易失性配置存储支持。凭借其 32 Mbit 的大容量与出色的系统兼容性&#xff0c;该芯片成为中高端 FP…

重复文件清理工具,附免费链接

链接:https://pan.baidu.com/s/1s_Zx1eHp5Y-XnbbGldIgvw?pwdkjex 提取码:kjex 复制这段内容后打开百度网盘手机App&#xff0c;操作更方便哦

【Spring Boot 快速入门】二、请求与响应

目录请求响应请求Postman 工具简单参数请求实体参数请求数组集合参数日期参数JSON 参数路径参数响应请求响应 请求 Postman 工具 Postman 是一款功能强大的网页调试与发送网页 HTTP 请求的 Chrome 插件 作用&#xff1a;常用于进行接口测试 简单参数请求 原始方式 在原始的…

高并发系统技术架构

&#xff08;点个赞&#xff0c;算法会给你推荐更多类似干货 ~&#xff09; 口诀&#xff1a; CDN 扛静态&#xff0c;WAF 防恶意&#xff1b;验证码拦机器&#xff1b; Nginx 先限流&#xff0c;Sentinel 再熔断&#xff1b; Redis 扣库存&#xff0c;MQ 异步写&#xff1b; 对…

python任意模块间采用全局字典来实现借用其他类对象的方法函数来完成任务或数据通信的功能

我们在编写pthon代码时&#xff0c;模块间的数据通信主要采用以下几种方法&#xff1a;1、采用全局变量。所有模块都通过引用全局变量&#xff0c;通过本模块对此全局变量数据的修改值&#xff0c;其他模块也能访问并得到此全局变量的当前值&#xff0c;由于全局变量的不可控性…

linux 部署 flink 1.15.1 并提交作业

下载 1.15.1 https://flink.apache.org/downloads.html#apache-flink-1151 部署模式分类 会话模式应用模式单作业模式 1、会话模式 先启动一个集群&#xff0c;保持一个会话&#xff0c;然后通过客户端提交作业&#xff0c;所有作业都在一个会话执行&#xff1b; 会话模式适合规…

Redis数据量过大的隐患:查询会变慢吗?如何避免?

一、Redis数据过多引发的五大隐患&#xff08;附系统交互图&#xff09; #mermaid-svg-X83bpHUu830QXKUt {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-X83bpHUu830QXKUt .error-icon{fill:#552222;}#mermaid-svg-…

网络与信息安全有哪些岗位:(3)安全运维工程师

安全运维工程师是企业安全防线的 “日常守护者”&#xff0c;既要确保安全设备与系统的稳定运行&#xff0c;又要实时监控潜在威胁&#xff0c;快速响应并处置安全事件&#xff0c;是连接安全技术与业务运营的关键角色。其核心价值在于通过常态化运维&#xff0c;将安全风险控制…

鱼皮项目简易版 RPC 框架开发(三)

本文为笔者阅读鱼皮的项目 《简易版 RPC 框架开发》的笔记&#xff0c;如果有时间可以直接去看原文&#xff0c; 1. 简易版 RPC 框架开发 前面的内容可以笔者的前面两个篇笔记 鱼皮项目简易版 RPC 框架开发&#xff08;一&#xff09; 鱼皮项目简易版 RPC 框架开发&#xff08;…

嵌入式Linux:注册线程清理处理函数

在 Linux 多线程编程中&#xff0c;线程终止时可以执行特定的清理操作&#xff0c;通过注册线程清理函数&#xff08;thread cleanup handler&#xff09;来实现。这类似于使用 atexit() 注册进程终止处理函数。线程清理函数用于在线程退出时执行一些资源释放或清理工作&#x…

【Git】Linux-ubuntu 22.04 初步认识 -> 安装 -> 基础操作

文章目录Git 初识Git 安装Linux-centosLinux-ubuntuWindowsGit 基本操作配置 Git认识工作区、暂存区、版本库添加文件 -- 场景一查看 .git 文件添加文件 -- 场景二修改文件版本回退撤销修改情况一&#xff1a;对于工作区的代码&#xff0c;还没有 add情况二&#xff1a;已经 ad…

轻量级音乐元数据编辑器Metadata Remote

简介 什么是 Metadata Remote (mdrm) &#xff1f; Metadata Remote 是一个基于 Web 的音频元数据编辑工具&#xff0c;旨在简化在无头服务器&#xff08;即没有图形用户界面的服务器&#xff09;上编辑音频文件的元数据。用户只需使用 Docker 和浏览器&#xff0c;无需复杂的…

免费使用|共享服务器上线RTX3080(20GB显存)

共享服务器也上架GPU啦 生物信息学中有很多用到GPU的场景&#xff0c;例如我们分享过的&#xff1a;利用GPU加速TensorFlow、部署本地DeepSeek&#xff0c;空间转录组学习手册合辑加速。因此多种GPU供大家选择&#xff1a;RTX5090、4080S、5070显卡上机。为了让此前的CPU服务器…

搭建DM数据守护集群

1环境与规划准备3个kylin 10操作系统的虚拟机&#xff0c;规划IP、端口、安装目录等。说明搭建REALTIME归档模式、事务一致性的数据守护名称项初始主库机器dm1初始备库机器dm2监视器机器dmmon外部业务IP192.168.23.129192.168.23.130192.168.23.131内部心跳IP192.168.23.129192…

AUTOSAR进阶图解==>AUTOSAR_SRS_OCUDriver

AUTOSAR OCU驱动程序详解 AUTOSAR标准输出比较单元驱动程序架构与实现分析目录 1. 概述 1.1 OCU驱动程序简介1.2 功能概述 2. OCU驱动程序架构 2.1 架构图2.2 层次结构 3. OCU驱动程序组件设计 3.1 组件图3.2 接口定义 4. OCU驱动程序状态管理 4.1 状态图4.2 状态转换 5. OCU驱…

InfluxDB 与 HTTP 协议交互进阶(一)

引言 在当今数字化时代&#xff0c;数据处理的高效性和准确性成为了众多领域关注的焦点。InfluxDB 作为一款开源的时序数据库&#xff0c;凭借其高性能、易扩展等特性&#xff0c;在时间序列数据处理中占据了重要地位。而 HTTP 协议作为互联网应用层的核心协议之一&#xff0c…

NAS远程访问新解法:OMV与cpolar的技术协同价值

文章目录前言1. OMV安装Cpolar2. 配置FTP公网地址3. OMV FTP 配置4. OMV FTP远程连接前言 当家庭存储需求突破本地边界时&#xff0c;传统NAS方案往往陷入"连接困境"&#xff1a;复杂的端口转发配置、高昂的公网IP成本、以及始终存在的安全顾虑…开源解决方案OMV虽然…

vue 渲染 | 不同类型的元素渲染的方式(vue组件/htmlelement/纯 html)

省流总结&#xff1a;&#xff08;具体实现见下方&#xff09; vue 组件 ——》<component :is组件名> htmlelement 元素 ——》 ref 、★ v-for ref 或是 ★ vue 的 nextTick 纯 html 结构——》v-html 另外&#xff0c;当数据异步加载时&#xff0c;vue3中如何渲…

Charles中文版深度解析,轻松调试API与优化网络请求

在现代软件开发过程中&#xff0c;调试API、捕获HTTP/HTTPS流量以及优化网络性能是开发者不可避免的挑战。特别是在处理复杂的网络请求和验证API接口的数据传输准确性时&#xff0c;开发者需要一款强大且易于使用的工具。Charles抓包工具凭借其功能强大、界面简洁、易于操作的特…

【CF】Codeforces Round 1039 (Div. 2) E1 (二分答案求中位数)

E1. Submedians (Easy Version)题目&#xff1a;思路&#xff1a;经典不过加了点东西对于求中位数&#xff0c;我们必然要想到二分答案&#xff0c;具体的&#xff0c;对于所有大于等于 x 的数我们令其奉献为 1&#xff0c;小于的为 -1&#xff0c;如果存在某段区间的奉献和大于…