8.2 生成器函数与表达式:Python 的秘密武器

news2024/9/25 7:13:42

欢迎来到我的博客,很高兴能够在这里和您见面!欢迎订阅相关专栏:
工💗重💗hao💗:野老杂谈
⭐️ 全网最全IT互联网公司面试宝典:收集整理全网各大IT互联网公司技术、项目、HR面试真题.
⭐️ AIGC时代的创新与未来:详细讲解AIGC的概念、核心技术、应用领域等内容。
⭐️ 全流程数据技术实战指南:全面讲解从数据采集到数据可视化的整个过程,掌握构建现代化数据平台和数据仓库的核心技术和方法。
⭐️ 构建全面的数据指标体系:通过深入的理论解析、详细的实操步骤和丰富的案例分析,为读者提供系统化的指导,帮助他们构建和应用数据指标体系,提升数据驱动的决策水平。
⭐️《遇见Python:初识、了解与热恋》 :涵盖了Python学习的基础知识、进阶技巧和实际应用案例,帮助读者从零开始逐步掌握Python的各个方面,并最终能够进行项目开发和解决实际问题。

摘要

在 Python 的世界里,生成器是一个能让你写出高效、优雅代码的秘密武器。生成器函数和生成器表达式不仅能节省内存,还能让你的代码更加灵活。本篇文章将带你深入了解生成器的工作原理,并通过生动的示例和幽默的语言,帮助你轻松掌握这一强大工具。

标签: Python、生成器、内存管理、惰性计算、函数编程


什么是生成器?

生成器函数:从 returnyield

在 Python 中,我们习惯了用 return 来结束一个函数并返回结果。然而,yield 的出现让我们多了一种选择。yield 就像是一个暂停按钮,它能让函数在某个时刻“冻结”当前状态,并返回一个值。更神奇的是,下次你再调用这个函数时,它会从“暂停”的位置继续运行。

举个简单的例子,假设你想要生成一系列的数字,但不想一次性生成所有数字,而是每次只生成一个。这个时候,yield 就派上用场了。

def simple_generator():
    yield 1
    yield 2
    yield 3

gen = simple_generator()

print(next(gen))  # 输出: 1
print(next(gen))  # 输出: 2
print(next(gen))  # 输出: 3
故事:旅行者与暂停按钮

想象一下,你是一个世界旅行者,每到一个城市,你都会停下来拍照并发一条朋友圈。每次发完朋友圈,你就暂停旅行,直到收到点赞后才继续前进。这种“走走停停”的旅行方式,正是生成器的运行逻辑。

生成器函数的优势

内存效率:按需生成

生成器最大的优势之一就是内存效率。传统的函数会一次性返回所有结果,这意味着你需要为所有的结果分配内存。而生成器则不同,它们只在需要时才生成结果,从而节省了大量的内存。

比如,如果你要生成一个包含百万个数字的列表,用传统方法很容易让内存吃紧。而用生成器函数,这一切都变得轻松了。

def large_range(n):
    for i in range(n):
        yield i

gen = large_range(1000000)

print(next(gen))  # 输出: 0
print(next(gen))  # 输出: 1
# ...直到你遍历完所有数字
惰性计算:不浪费一滴计算力

生成器的另一个优势是惰性计算。它们只在需要时才计算下一步结果,而不会提前做无谓的工作。这就像是懒惰的学生,只有考试前一晚才开始复习,但每次都能刚好考到及格线。

这种特性在处理实时数据或流式数据时特别有用,比如你要从一个无限数据流中获取数据,但你只需要其中的前十个。用生成器,这就变得非常简单。

import itertools

def infinite_numbers():
    num = 0
    while True:
        yield num
        num += 1

gen = infinite_numbers()

for i in itertools.islice(gen, 10):
    print(i)  # 输出: 0 到 9

生成器表达式

生成器表达式:列表解析的轻量级兄弟

生成器表达式看起来和列表解析非常相似,但它们之间有一个关键的区别:列表解析一次性生成整个列表,而生成器表达式则是按需生成元素。这使得生成器表达式更加节省内存。

# 列表解析
squares_list = [x * x for x in range(10)]
print(squares_list)  # 输出: [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

# 生成器表达式
squares_gen = (x * x for x in range(10))
print(next(squares_gen))  # 输出: 0
print(next(squares_gen))  # 输出: 1
# ...直到遍历完所有元素
组合生成器表达式

生成器表达式可以像乐高积木一样组合使用,让你在实现复杂逻辑时还能保持代码的简洁。

# 生成一个生成器表达式的生成器
nested_gen = ((i, j) for i in range(3) for j in range(2))

for item in nested_gen:
    print(item)  # 输出: (0, 0), (0, 1), (1, 0), (1, 1), (2, 0), (2, 1)
故事:无限大餐与小勺子

想象你来到了一家无限供应美食的餐厅,但餐厅给你提供的是一个小勺子,而不是大盘子。每次你想吃一口,就用小勺子舀一勺。这就是生成器表达式的工作原理:你只获取当前需要的一口,而不是整个盘子里的食物。

生成器的高级用法

多个 yield 的组合

生成器函数可以使用多个 yield 来实现复杂的逻辑。比如,你可以在一个生成器中调用另一个生成器,从而实现嵌套的生成。

def countdown(n):
    while n > 0:
        yield n
        n -= 1

def counter(start, end):
    yield from countdown(start)
    yield from range(end - start)

gen = counter(5, 10)

for value in gen:
    print(value)  # 输出: 5, 4, 3, 2, 1, 5, 6, 7, 8, 9
使用生成器模拟无限流

生成器非常适合用来模拟无限数据流。比如,你可以用生成器来模拟一个无限的随机数流。

import random

def random_numbers():
    while True:
        yield random.randint(1, 100)

gen = random_numbers()

for _ in range(5):
    print(next(gen))  # 每次运行输出不同的随机数

生成器在实际中的应用

处理大文件

生成器在处理大文件时非常有用。假设你需要逐行处理一个非常大的文件,用生成器可以避免一次性加载整个文件,从而节省内存。

def read_large_file(file_path):
    with open(file_path, 'r') as file:
        for line in file:
            yield line.strip()

for line in read_large_file('large_file.txt'):
    print(line)
数据流的实时处理

在数据流处理中,生成器可以帮助我们实时处理数据而不是等到所有数据都到达后再处理。

def process_sensor_data():
    while True:
        data = get_sensor_data()  # 假设这是一个实时获取传感器数据的函数
        yield data

for data in process_sensor_data():
    if data > threshold:  # 处理超过阈值的数据
        alert(data)

生成器的局限性与注意事项

一次性消耗

生成器是一次性的。也就是说,一旦你遍历了生成器,它的内容就消失了,想要再用就得重新生成。

gen = (x for x in range(3))

print(list(gen))  # 输出: [0, 1, 2]
print(list(gen))  # 输出: []
调试的挑战

生成器的惰性计算特性有时会让调试变得更加复杂,尤其是在生成器中混入了复杂的逻辑时。

总结——掌握生成器的精髓

通过本文的讲解,你应该已经掌握了生成器函数与生成器表达式的基本概念、优势以及在实际编程中的应用。生成器让你的代码更加高效、灵活,并且可以处理大量数据而不占用过多内存。

Python 的生成器概念虽然简单,但其应用范围广泛。无论是新手还是老手,都可以通过掌握生成器来提升编程技巧。继续探索和应用这些强大的工具吧,Python 的世界无穷无尽!


在这里插入图片描述

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

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

相关文章

使用jlink高版本调试和烧录立创·地文星CW32F030C8T6开发板

使用jlink高版本调试和烧录立创地文星CW32F030C8T6开发板 CW32F030固件包下载 下载地址:https://www.whxy.com/uploads/files/20240514/CW32F030_StandardPeripheralLib_V2.1.zip 官网资料地址:固件库-武汉芯源半导体官网|专注32位MCU芯片设计 (whxy.…

提升树模型

提升树(Boosting Tree)是一种集成学习方法,它通过组合多个弱分类器(通常是决策树)来构建一个强分类器。这种方法在许多统计学习任务中表现出色,被认为是性能最好的方法之一。 提升树模型概述 提升树模型是…

我的世界 java 1.21 版本中 function 命令介绍使用教程

仅限java中的1.21版本 一、函数文件位置二、创建配置和函数文件1.函数名称.mcfunction2.pack.mcmeta【默认文件】 三、加载执行函数1.刷新数据包,重新加载2.查询数据包加载情况3.执行函数 四、特别感谢 特别注意,在1.21版本中function目录名没有s&#x…

Katalon Studio 使用教程(小白快速入门版)

如果你还没有安装,可以点击下方安装教程链接,里面有详细的安装链接与教程: Katalon Studio 保姆级安装教程-CSDN博客 安装好后,应当是这样的界面。本篇从安装好后开始讲。 katalon的使用很简单,三步就能实现一个完整的…

网络原理(2)——封装和分用

1. 数据在网络通信中的整体流程:封装和分用 例子:通过 QQ 发送一个 hello 给另一个人 a) 发送方视角 1. 用户在输入框中输入 “hello” 字符串,点击发送按钮 QQ 这样的程序就会把 hello 这个内容从输入框读取到,并构造成一个“…

关于dubbo3.x端口绑定22222报错问题

目录 1.报错信息如下 2.由于每个dubbo应用注册的时候都当做一个qos-server ,有一个固定的端口号,默认是22222, 不同应用需要设置不同的端口号 3.在application.yml,或者在application.properties指定就好了(修改qos…

PUMA论文阅读

PUMA: Efficient Continual Graph Learning with Graph Condensation PUMA:通过图压缩进行高效的连续图学习 ABSTRACT 在处理流图时,现有的图表示学习模型会遇到灾难性的遗忘问题,当使用新传入的图进行学习时,先前学习的这些模…

Redis6-秒杀

目录 全局唯一ID 实现优惠券秒杀下单 超卖问题 一人一单 全局唯一ID 全局ID生成器,是一种在分布式系统下用来生成全局唯一ID的工具,一般要满足下列特性: 为了增强ID的安全性,不直接使用Redis自增的数值,而是拼接一…

告别数据丢失烦恼,转转数据恢复和另外三款工具助你一臂之力!

不知道大伙儿有没有和我一样,到哪都喜欢拍照片和视频,加上办公上也是七七八八的各种格式的文件实在是多,所以电脑和手机等等设备上经常内存爆满需要清理,难免会出现不小心误删或者格式化、清空等等的情况,用过几款和转…

微服务实现-sleuth+zipkin分布式链路追踪和nacos配置中心

1. sleuthzipkin分布式链路追踪 在大型系统的微服务化构建中,一个系统被拆分成了许多微服务。这些模块负责不同的功能,组合成系统,最终可以提供丰富的功能。 这种架构中,一次请求往往需要涉及到多个服务。互联网应用构建在不同的软…

嵌入式day22

getpwuid 通过uid 获取用户名 uid 用户uid 返回值: 成功 返回用户名 失败 NULL getgrgid 通过gid 获取组名 gid 组名gid 返回值: 成功 返回组名 失败 NULL 1、获取秒数 2、转换为需要的格式 time 获得1970年到现在的秒数(系统时间…

IEC103设备数据 转 CCLink IE Field Basic项目案例

目录 1 案例说明 1 2 VFBOX网关工作原理 1 3 准备工作 2 4 配置VFBOX网关采集103设备数是 2 5 使用CCLINK协议转发数据 4 6 三菱PLC连接网关的CCLINK的设置 5 7 IEC103协议说明 9 8 案例总结 10 1 案例说明 设置网关采集IEC103设备数据把采集的数据转成CCLink IE Field Basic…

UDP服务器实现

目录 一、服务端创建 1.1、创建套接字 1.2、端口绑定 1.3、sockaddr_in结构体 1.4、字符串IP和整数IP说明 1.5、绑定好端口号的服务端代码 1.6、服务端代码 二、客户端创建 2.1、关于客户端的绑定问题 2.2、客户端代码 一、服务端创建 首先明确,这个简单…

ThinkPad T14p Gen1(21J7,21N3)原厂Windows11系统镜像下载

LENOVO联想ThinkPad 系列笔记本电脑原装出厂Win11系统安装包,恢复出厂开箱状态预装OEM系统 适用型号:T14p Gen1【21J7,21N3】 链接:https://pan.baidu.com/s/1bLHdQoQ9zsAeZgd4c0ie4A?pwdxps2 提取码:xps2 联想原装WIN系统自…

QT 布局管理器之QHBoxLayout

文章目录 概述.ui来看看Cmain.cpp运行 小结 概述 QHBoxLayout,在QT中是一个布局文件,而且相对来说还是比较简单的。接下来看下。 .ui 先看下在qt design中是如何用的,如下图: 就是这个布局文件,是一个xml的文件&am…

Redis之golang编程实战

Redis 介绍 官网:Redis - The Real-time Data Platform Redis 可作为数据库、缓存、流引擎和消息代理的开源内存数据存储。被用在不计其数的应用中。Redis 连续 5 年被评为最受欢迎的数据库,是开发人员、架构师和开源贡献者参与社区的中心。 Redis 是…

苹果计划推出付费版Apple Intelligence AI服务,费用高达20美元

本文首发于公众号“AntDream”,欢迎微信搜索“AntDream”或扫描文章底部二维码关注,和我一起每天进步一点点 苹果计划推出付费版Apple Intelligence AI服务 苹果公司正在计划推出一项新的高级人工智能服务,名为Apple Intelligence&#xff0…

关于嵌套循环之深入理解

关于嵌套循环之深入理解 # 外层循环遍历第一维(深度) for depth in range(len(cube)):# 中层循环遍历第二维(行)for row in range(len(cube[depth])):# 内层循环遍历第三维(列)for col in range(len(cube[d…

秒懂C++之进程状态及优先级

目录 一.进程状态 1.1 进程排队 1.2 进程状态 运行状态 阻塞状态 挂起状态 二.Linux环境下的进程状态 R运行状态 S睡眠状态 D磁盘休眠状态 T停止状态 X死亡状态 Z僵尸进程状态 三.进程优先级 基本概念 查看系统进程 用top命令更改已存在进程的nice 一.进程状态…

【数据结构】十大排序全面分析讲解及其对比分析(排序看懂就这篇!)

【数据结构】十大排序全面分析讲解及其对比分析 🔥个人主页:大白的编程日记 🔥专栏:数据结构 文章目录 【数据结构】十大排序全面分析讲解及其对比分析前言一.排序的概念及其运用1.1排序的概念1.2排序的应用 二.插入排序2.1 插入…