深入理解Python生成器(Generator)

我们可以通过列表生成式简单直接地创建一个列表,但是受到内存限制,列表容量肯定是有限的。而且,创建一个包含100万个元素的列表,不仅占用很大的存储空间,而且如果我们仅仅需要访问前面几个元素,那后面绝大多数元素占用的空间都白白浪费了。

所以,如果列表元素可以按照某种算法推算出来,那我们是否可以在循环的过程中不断推算出后续的元素呢?这样就不必创建完整的list,从而节省大量的空间。在Python中,这种一边循环一边计算的机制,称为生成器(Generator)。

要创建一个generator,有很多种方法。第一种方法很简单,只要把一个列表生成式的[]改成(),就创建了一个generator:

>>> mylist = [ x for x in range(1, 10)]>>> mylist[1, 2, 3, 4, 5, 6, 7, 8, 9]>>> gen = (x for x in range(1,10))>>> gen at 0x7f1d7fd0f5a0>

登录后复制

创建mylist和gen的区别仅在于最外层的[]和(),mylist是一个list,而gen是一个generator(生成器)。

我们可以直接打印出list的每一个元素,但我们怎么打印出generator的每一个元素呢?

立即学习“Python免费学习笔记(深入)”;

如果要一个一个打印出来,可以通过generator的next()方法:

>>> gen.next()1>>> gen.next()2>>> gen.next()3...>>> gen.next()9>>> gen.next()Traceback (most recent call last):  File "", line 1, in StopIteration

登录后复制

我们讲过,generator保存的是算法,每次调用next(),就计算出下一个元素的值,直到计算到最后一个元素,没有更多的元素时,抛出StopIteration的错误。

其实我们可以使用for循环来代替next()方式, 这样才更符合高效的编程思路:

>>> gen = ( x for x in range(1, 10))>>> for num in gen:...     print num... 123456789

登录后复制

generator非常强大。如果推算的算法比较复杂,用类似列表生成式的for循环无法实现的时候,还可以用函数来实现。

比如,著名的斐波拉契数列(Fibonacci),除第一个和第二个数外,任意一个数都可由前两个数相加得到:

1, 1, 2, 3, 5, 8, 13, 21, 34, …

斐波拉契数列用列表生成式写不出来,但是,用函数把它打印出来却很容易:

def fib(max):    n = 0     a, b = 0, 1    while n 

上面的函数可以输出斐波那契数列的前N个数:

>>> fib(6)

登录后复制

仔细观察,可以看出,fib函数实际上是定义了斐波拉契数列的推算规则,可以从第一个元素开始,推算出后续任意的元素,这种逻辑其实非常类似generator。

也就是说,上面的函数和generator仅一步之遥。要把fib函数变成generator,只需要把print b改为yield b就可以了:

def fib(max):    n = 0     a, b = 0, 1    while n 

这就是定义generator的另一种方法。如果一个函数定义中包含yield关键字,那么这个函数就不再是一个普通函数,而是一个generator:

>>> fib(6)

登录后复制

这里,最难理解的就是generator和函数的执行流程不一样。函数是顺序执行,遇到return语句或者最后一行函数语句就返回。而变成generator的函数,在每次调用next()的时候执行,遇到yield语句返回,再次执行时从上次返回的yield语句处继续执行。

举个简单的例子,定义一个generator,依次返回数字1,3,5:

>>> def odd():...     print 'step 1'...     yield 1...     print 'step 2'...     yield 3...     print 'step 3'...     yield 5...>>> o = odd()>>> o.next()step 11>>> o.next()step 23>>> o.next()step 35>>> o.next()Traceback (most recent call last):  File "", line 1, in StopIteration

登录后复制

可以看到,odd不是普通函数,而是generator,在执行过程中,遇到yield就中断,下次又继续执行。执行3次yield后,已经没有yield可以执行了,所以,第4次调用next()就报错。

回到fib的例子,我们在循环过程中不断调用yield,就会不断中断。当然要给循环设置一个条件来退出循环,不然就会产生一个无限数列出来。

同样的,把函数改成generator后,我们基本上从来不会用next()来调用它,而是直接使用for循环来迭代:

>>> for n in fib(6):...     print n...

登录后复制

generator是非常强大的工具,在Python中,可以简单地把列表生成式改成generator,也可以通过函数实现复杂逻辑的generator。

要理解generator的工作原理,它是在for循环的过程中不断计算出下一个元素,并在适当的条件结束for循环。对于函数改成的generator来说,遇到return语句或者执行到函数体最后一行语句,就是结束generator的指令,for循环随之结束。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至253000106@qq.com举报,一经查实,本站将立刻删除。

发布者:PHP中文网,转转请注明出处:https://www.chuangxiangniao.com/p/2283229.html

(0)
上一篇 2025年2月27日 20:01:37
下一篇 2025年2月27日 20:01:55

AD推荐 黄金广告位招租... 更多推荐

相关推荐

  • vscode怎么远程调试python代码?方法整理

    在《vscode远程gdb调试》文章中,介绍了如何使用 vscode 调试 c/c++ 代码,作为该文的姊妹篇,本文对调试 python 代码的方法做一个整理。 环境配置 远程连接的方法同 《vscode远程gdb调试》中的第 1 节相同,…

    2025年3月30日 编程技术
    100
  • sublime怎么输出

    在 Sublime Text 中输出内容有三种方法:在“控制台”面板中使用 print() 语句输出。设置断点并通过调试器的“控制台”选项卡查看输出。重定向 stdout 并通过输出面板查看输出。 如何在 Sublime Text 中输出内…

    2025年3月30日
    100
  • notepad怎么转换为json

    Notepad无法直接将文本转换为JSON。你可以通过检查文本是否符合JSON语法,使用JSON验证器或编程语言进行转换。如果数据是逗号分隔的,可以使用脚本解析数据并转换为JSON格式。 Notepad本身无法直接将文本转换为JSON。No…

    2025年3月30日
    100
  • vscode 和 visual studio 哪个更好

    根据具体需求和项目规模,选择最适合的 IDE:大型项目(尤其是 C#、C++)和复杂调试:Visual Studio,提供强大调试功能和对大型项目的完美支持。小型项目、快速原型开发、配置较低机器:VS Code,轻量级、启动速度快、资源占用…

    2025年3月30日
    100
  • vscode 无法运行 python怎么回事

    最常见的“无法运行 Python”问题源于 Python 解释器路径的错误配置,解决方法包括:确认 Python 安装、配置 VS Code、使用虚拟环境。除此之外,还有断点调试、变量监视、日志输出、代码格式化等高效的调试技巧和最佳实践,如…

    2025年3月30日
    100
  • JSON 差异:比较和识别 JSON 数据中的更改

    JSON(JavaScript 对象表示法)是一种广泛应用于数据传输和存储的结构化数据格式,尤其在Web开发领域。然而,对比两个JSON文件或结构,特别是处理嵌套或复杂数据时,往往充满挑战。JSON差异比较(JSON diff)正是为此而生…

    2025年3月30日
    100
  • Notepad++ 怎么以json格式显示数据

    Notepad++ 无法直接以 JSON 格式显示数据,而是文本编辑器,专注于编程语言语法高亮。查看 JSON 数据的有效方法包括:在线 JSON 格式化工具:简单易用,但可能速度较慢,安全性待考虑。支持 JSON 的代码编辑器:提供语法高…

    2025年3月30日
    100
  • 如何去除JSON数据中外层“other”关键字?

    去除JSON数据外层“other”关键字,保留原始数据 本文介绍如何高效地移除JSON数据中的外层“other”关键字,同时完整保留其内部数据结构。 问题描述: 给定一个JSON数据,其结构如下: { “other”: { “name”: …

    2025年3月30日
    100
  • MongoDB快速入门:从安装到基本操作

    本文介绍了mongodb的快速上手方法。1. 安装mongodb:下载对应版本安装包并运行安装程序,启动mongodb服务;2. 基本操作:使用pymongo驱动程序进行crud操作(插入、查询、更新、删除),注意连接和关闭数据库;3. 性…

    2025年3月30日
    100
  • Python 实现语音识别工具的不同技术方案

    Python 实现语音识别工具的不同技术方案:深度剖析与实践 很多开发者都想过构建一个属于自己的语音识别工具,这听起来很酷,对吧?但实际操作中,你会发现选择合适的技术方案至关重要,它直接影响着你的工具的准确率、效率,甚至最终的易用性。这篇文…

    2025年3月30日
    100

发表回复

登录后才能评论