百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 编程网 > 正文

一文掌握Python 生成器_python3 生成器

yuyutoo 2025-02-19 14:28 4 浏览 0 评论

ython 生成器有助于实现维护持久状态的功能。这支持增量计算和迭代。此外,可以使用生成器代替数组以节省内存。这是因为生成器不存储值,而是存储具有函数状态的计算逻辑,类似于准备触发的未计算函数实例。

生成器表达式

可以使用生成器表达式代替数组创建操作。与数组不同,生成器将在运行时生成数字。

>>> import sys
>>> a = [x for x in range(1000000)]
>>> b = (x for x in range(1000000))
>>> sys.getsizeof(a)
8697472
>>> sys.getsizeof(b)
128
>>> a
[0, 1, ... 999999]
>>> b
 at 0x1020de6d0>

我们可以看到,在上面的场景中,我们通过使用生成器代替数组节省了相当多的内存。

用 yield 代替 return 的函数

让我们考虑一个简单的例子,你想生成任意数量的素数。以下是检查一个数字是否为素数的函数以及将为我们产生无限多个素数的生成器。

def isPrime(n):
    if n < 2 or n % 1 > 0:
        return False
    elif n == 2 or n == 3:
        return True
    for x in range(2, int(n**0.5) + 1):
        if n % x == 0:
            return False
    return Truedef getPrimes():
    value = 0
    while True:
        if isPrime(value):
            yield value
        value += 1

正如你在第二个函数中看到的,我们在 while 循环中迭代并产生质数。让我们看看如何使用上面的生成器。

primes = getPrimes()>>> next(primes)
2
>>> next(primes)
3
>>> next(primes)
5

首先,我们调用函数并获取生成器实例。虽然这可以模拟无限数组,但目前还没有找到任何元素。如果调用 list(primes),程序可能会因 MemoryError 而崩溃。但是,对于素数,它不会去那里,因为素数空间是稀疏的,计算可以在有限的时间内达到内存限制。但是,对于发电机,您不会事先知道长度。如果你调用 len(primes),你将得到以下错误,原因与数字仅在运行时生成的原因相同。

----------------------------------------------------------------
TypeError                      Traceback (most recent call last)
 in 
----> 1 len(primes)

TypeError: object of type 'generator' has no len()

迭代次数有限的生成器

尽管我们的素数示例具有无限的迭代空间,但在大多数日常场景中,我们面临的是有限计算。因此,让我们看一个示例,我们可以使用它来读取包含文本数据的文件以及下一行句子的语义分数。

为什么我们需要使用 yield?

假设文件为 1TB,单词语料库为 500000。它不适合内存。一个简单的解决方案是一次读取 2 行,计算每行的单词字典,并在下一行返回语义分数。该文件将如下所示。

The product is well packed
5
Edges of the packaging was damaged and print was faded.
3
Avoid this product. Never going to buy anything from ShopX.
1
Shipping took a very long time
2

很明显,我们不需要立即打开文件。此外,这些行必须矢量化,并可能保存到另一个文件中,该文件可以直接解析以训练机器学习模型。因此,为我们提供干净代码的选项是使用一个生成器,该生成器将一次读取两行,并将数据和语义分数作为元组提供给我们。

实现文件解析生成器

假设我们在名为 test.txt 的文件中有上述文本文档。我们将使用以下生成器函数来读取文件。

def readData(path):
    with open(path) as f:
        sentiment = ""
        line = ""
        for n, d in enumerate(f):
            if n % 2 == 0:
                line = d.strip()
            else:
                sentiment = int(d.strip())
                yield line, sentiment

我们可以在 for 循环中使用上述函数,如下所示。

>>> data = readData("test.txt")
>>> for l, s in data: print(l, s)
The product is well packed 5
Edges of the packaging was damaged and print was faded. 3
Avoid this product. Never going to buy anything from ShopX. 1
Shipping took a very long time 2

生成器如何退出?

在正常的 for 循环中,当生成器不再执行 yielding 时,迭代将停止。但是,我们可以通过在生成器实例上手动调用 next() 来观察到这一点。在迭代限制之外调用 next() 将引发以下异常。

----------------------------------------------------------------
StopIteration                  Traceback (most recent call last)
 in 
---> 28 print(next(data))StopIteration:

使用 send、throw 和 close

send 函数

让我们回顾一下我们的素数示例。想象一下,我们想将生成器函数的值重置为 100,如果它们是质数,则开始产生大于 100 的值。我们可以在生成器实例上使用 send() 方法将值推送到生成器中,如下所示。

>>> primes = getPrimes()
>>> next(primes)
2
>>> primes.send(10)
11
>>> primes.send(100)
101

请注意,在调用 send() 之前,我们必须至少调用 next() 一次。让我们看看如何修改我们的函数以适应目的。因为函数应该知道如何分配接收到的值。

def getPrimes():
    value = 0
    while True:
        if isPrime(value):
            i = yield value
            if i is not None:
                value = i
        value += 1

我们将 yield 值存储在变量 i 中。如果不是 None 类型,我们将其分配给 value 变量。None 检查是必不可少的,因为第一个 next()value 变量中没有 value to yield。

throw 函数

假设您希望以大于 10 的值结束迭代,以避免溢出或超时(假设)。throw() 函数可用于提示生成器停止引发异常。

primes = getPrimes()for x in primes:
    if x > 10:
        primes.throw(ValueError, "Too large")
    print(x)

此技术可用于验证输入。逻辑在于生成器的用户。这将产生以下输出。

2
3
5
7----------------------------------------------------------------
ValueError                     Traceback (most recent call last)
 in 
     12 for x in primes:
     13     if x > 10:
---> 14         primes.throw(ValueError, "Too large")
     15     print(x)

 in getPrimes()
      3     while True:
      4         if isPrime(value):
----> 5             i = yield value
      6             if i is not None:
      7                 value = i

ValueError: Too large

close 函数

手头无一例外地处理瓶盖通常是优雅的。在这种情况下,close() 函数可用于有效地关闭迭代器。

primes = getPrimes()for x in primes:
    if x > 10:
        primes.close()
    print(x)

这将得到以下输出。

2
3
5
7
11

请注意,我们的值为 11,这是最后一个计算出的大于 11 的值。这模拟了 C/C++ 中 do while 循环的行为。

相关推荐

微软Win10/Win11版Copilot上线:支持OpenAI o3推理模型

IT之家4月3日消息,科技媒体WindowsLatest昨日(4月2日)发布博文,报道称Windows10、Windows11新版Copilot应用已摘掉Beta帽...

WinForm 双屏幕应用开发:原理、实现与优化

在当今的软件开发领域,多屏幕显示技术的应用越来越广泛。对于WinForm应用程序来说,能够支持双屏幕显示不仅可以提升用户体验,还能满足一些特定场景下的业务需求,比如在演示、监控或者多任务处理等场景...

推荐一个使用 C# 开发的 Windows10 磁贴美化小工具

...

OpenJDK 8 安装(openjdk 8 windows)

通常OpenJDK8和11都能互相编译和通用。我们建议使用11,但是如果你使用JDK8的话也是没有问题的。建议配置使用OpenJDK,不建议使用OracleJDK,主要是因为版...

基于 Linux 快速部署 OpenConnect VPN 服务(ocserv 实战指南)

一、前言在如今远程办公和内网穿透需求日益增长的背景下,搭建一套安全、稳定、高效的VPN系统显得尤为重要。OpenConnectServer(ocserv)是一个开源、高性能的VPN服务端软件...

巧妙设置让Edge浏览器更好用(edge怎么设置好用)

虽然现在新版本的Edge浏览器已经推出,但是毕竟还处于测试的状态中。而Win10系统里面自带的老版Edge浏览器,却越来越不被人重视。其实我们只需要根据实际情况对老版本的Edge浏览器进行一些简单的设...

WPF做一个漂亮的登录界面(wpf页面设计)

...

微软开源博客工具Open Live Writer更新:多项Bug修复

OpenLiveWriter前身是WindowsLiveWriter,是微软WindowsLive系列软件之一,曾经是博主们非常喜爱的一款所见即所得博文编辑工具,支持离线保存,还支持图像编辑...

基于OpenVINO的在线设计和虚拟试穿 | OPENAIGC大赛企业组优秀作品

在第二届拯救者杯OPENAIGC开发者大赛中,涌现出一批技术突出、创意卓越的作品。为了让这些优秀项目被更多人看到,我们特意开设了优秀作品报道专栏,旨在展示其独特之处和开发者的精彩故事。...

C#开源免费的Windows右键菜单管理工具

...

Windows10或11中隐藏的功能,用它再也不用担心电脑中病毒!

...

Python open函数详解(python open函数源码)

演示环境,操作系统:Win1021H2(64bit);Python解释器:3.8.10。open是Python的一个内置函数,一般用于本地文件的读写操作。用法如下。my_file=open(fi...

Windows 11 安装 Docker Desktop(Windows 11 安装助手 Windows 易升 关系)

...

Windows 11 新版发布:屏幕亮度自适应控制,小组件界面重新设计!

...

世界上最好用的Linux发行版之一,OpenSUSE安装及简单体验

背景之前无意在论坛里看到openSUSE的Linux发行版,被称为世界上最好用的Linux发行版之一(阔怕),一直想体验一下,于是这期做一个安装和简单体验教程吧。...

取消回复欢迎 发表评论: