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

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

yuyutoo 2025-02-19 14:28 1 浏览 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 循环的行为。

相关推荐

如何在HTML中使用JavaScript:从基础到高级的全面指南!

“这里是云端源想IT,帮你...

推荐9个Github上热门的CSS开源框架

大家好,我是Echa。...

前端基础知识之“CSS是什么?”_前端css js

...

硬核!知网首篇被引过万的论文讲了啥?作者什么来头?

整理|袁小华近日,知网首篇被引量破万的中文论文及其作者备受关注。知网中心网站数据显示,截至2021年7月23日,由华南师范大学教授温忠麟等人发表在《心理学报》2004年05期上的学术论文“中介效应检验...

为什么我推荐使用JSX开发Vue3_为什么用vue不用jquery

在很长的一段时间中,Vue官方都以简单上手作为其推广的重点。这确实给Vue带来了非常大的用户量,尤其是最追求需求开发效率,往往不那么在意工程代码质量的国内中小企业中,Vue占据的份额极速增长...

【干货】一文详解html和css,前端开发需要哪些技术?
【干货】一文详解html和css,前端开发需要哪些技术?

网站开发简介...

2025-02-20 18:34 yuyutoo

分享几个css实用技巧_cssli

本篇将介绍几个css小技巧,目录如下:自定义引用标签的符号重置所有标签样式...

如何在浏览器中运行 .NET_怎么用浏览器运行代码

概述:...

前端-干货分享:更牛逼的CSS管理方法-层(CSS Layers)

使用CSS最困难的部分之一是处理CSS的权重值,它可以决定到底哪条规则会最终被应用,尤其是如果你想在Bootstrap这样的框架中覆盖其已有样式,更加显得麻烦。不过随着CSS层的引入,这一...

HTML 基础标签库_html标签基本结构
HTML 基础标签库_html标签基本结构

HTML标题HTML标题(Heading)是通过-...

2025-02-20 18:34 yuyutoo

前端css面试20道常见考题_高级前端css面试题

1.请解释一下CSS3的flexbox(弹性盒布局模型),以及适用场景?display:flex;在父元素设置,子元素受弹性盒影响,默认排成一行,如果超出一行,按比例压缩flex:1;子元素设置...

vue引入外部js文件并使用_vue3 引入外部js

要在Vue中引入外部的JavaScript文件,可以使用以下几种方法:1.使用``标签引入外部的JavaScript文件。在Vue的HTML模板中,可以直接使用``标签来引入外部的JavaScrip...

网页设计得懂css的规范_html+css网页设计

在初级的前端工作人员,刚入职的时候,可能在学习前端技术,写代码不是否那么的规范,而在工作中,命名的规范的尤为重要,它直接与你的代码质量挂钩。网上也受很多,但比较杂乱,在加上每年的命名都会发生一变化。...

Google在Chrome中引入HTML 5.1标记

虽然负责制定Web标准的WorldWideWebConsortium(W3C)尚未宣布HTML5正式推荐规格,而Google已经迁移到了HTML5.1。即将发布的Chrome38将引入H...

HTML DOM 引用( ) 对象_html中如何引用js

引用对象引用对象定义了一个同内联元素的HTML引用。标签定义短的引用。元素经常在引用的内容周围添加引号。HTML文档中的每一个标签,都会创建一个引用对象。...

取消回复欢迎 发表评论: