当前位置: 首页 > news >正文

什么是生成器 — 一篇文章让你看懂

嗨嗨,我是小圆 ~ 今天来给大家讲讲什么是生成器

请添加图片描述

生成器是 Python 初级开发者最难理解的概念之一,虽被认为是 Python 编程中的高级技能,但在各种项目中可以随处见到生成器的身影,你得不得去理解它、使用它、甚至爱上它。

请添加图片描述

提到生成器,总不可避免地要把迭代器拉出来对比着讲,生成器就是一个在行为上和迭代器非常类似的对象,如果把迭代器比作 Android 系统,那么生成器就是 iOS,二者功能上差不多,但是生成器更优雅。

什么是迭代器

顾名思义,迭代器就是用于迭代操作(for 循环)的对象,它像列表一样可以迭代获取其中的每一个元素,任何实现了 next 方法
(python2 是 next)的对象都可以称为迭代器。

它与列表的区别在于,构建迭代器的时候,不像列表把所有元素一次性加载到内存,而是以一种延迟计算(lazy evaluation)方式返回元素,这正是它的优点。比如列表含有中一千万个整数,需要占超过400M的内存,而迭代器只需要几十个字节的空间。因为它并没有把所有元素装载到内存中,而是等到调用 next 方法时候才返回该元素(call by need 的方式),本质上 for 循环就是不断地调用迭代器的next方法。

以斐波那契数列为例来实现一个迭代器:

class Fib:
    def __init__(self, n):
        self.prev = 0
        self.cur = 1
        self.n = n

    def __iter__(self):
        return self

    def __next__(self):
        if self.n > 0:
            value = self.cur
            self.cur = self.cur + self.prev
            self.prev = value
            self.n -= 1
            return value
        else:
            raise StopIteration()

f = Fib(10)
print([i for i in f])
#[1, 1, 2, 3, 5, 8, 13, 21, 34, 55]

什么是生成器

知道迭代器之后,就可以正式进入生成器的话题了。普通函数用 return 返回一个值,和 Java 等其他语言是一样的,然而在 Python 中还有一种函数,用关键字 yield 来返回值,这种函数叫生成器函数,函数被调用时会返回一个生成器对象,生成器本质上还是一个迭代器,也是用在迭代操作中,因此它有和迭代器一样的特性,唯一的区别在于实现方式上不一样,后者更加简洁

最简单的生成器函数:

>>> def func(n):
...     yield n*2
...
>>> func
<function func at 0x00000000029F6EB8>
>>> g = func(5)
>>> g
<generator object func at 0x0000000002908630>
>>>

func 就是一个生成器函数,调用该函数时返回对象就是生成器 g ,这个生成器对象的行为和迭代器是非常相似的,可以用在 for 循环等场景中。注意 yield 对应的值在函数被调用时不会立刻返回,而是调用next方法时(本质上 for 循环也是调用 next 方法)才返回

>>> g = func(5)
>>> next(g)
10

>>> g = func(5)
>>> for i in g:
...     print(i)
...
10

那为什么要用生成器呢?显然,用生成器在逼格上要比迭代器高几个等级,它没有那么多冗长代码了,而且性能上一样的高效,为什么不用呢?来看看用生成器实现斐波那契数列有多简单。

def fib(n):
    prev, curr = 0, 1
    while n > 0:
        n -= 1
        yield curr
        prev, curr = curr, curr + prev

print([i for i in fib(10)])
#[1, 1, 2, 3, 5, 8, 13, 21, 34, 55]

生成器表达式

生成器表达式与列表推导式长的非常像,但是它俩返回的对象不一样,前者返回生成器对象,后者返回列表对象。

>>> g = (x*2 for x in range(10))
>>> type(g)
<type 'generator'>
>>> l = [x*2 for x in range(10)]
>>> type(l)
<type 'list'>

好了,这篇文章分享到这里就结束了 ~

我是小圆,我们下篇文章见 ~

在这里插入图片描述

相关文章:

  • 国内近五年人工智能教育的研究热点及趋势——基于多维尺度和社会网络分析的方法
  • QGraphicsItem鼠标拖动旋转(五)
  • win7连接打印机0x0000011b错误的解决办法
  • 四、RocketMq本地集群搭建:多master-slaver异步
  • pcan二次开发文档 | PEAK-System Documentation
  • R语言数据分组聚合实战:使用aggregate函数对mtcars数据通过两个分类变量进行数据分组聚合、并计算分组的均值、使用na.rm删除异常值
  • Chapter15 : Artificial Intelligence in Compound Design
  • 前端HTML5 +CSS3 1. 基础认知
  • R语言替换字符串中指定字符的子串:sub函数查找字符串中第一个匹配到的子串并替换、如果要删除指定字符串子串则将替换的子符串设置为空字符串
  • java计算机毕业设计基于springboo大学生社团管理系统 vue+elementui
  • un9.2:创建springboot的两种方式。
  • dubbo的Failed to save registry store file问题
  • HTML期末作业 计算机毕业设计 html css javascript食品餐饮行业网站(10页)
  • 搭建和mybatis-plus官网一样主题的网站(cos+宝塔+vercel)
  • 股权重组是指什么
  • classpath对获取配置文件的影响
  • Fastjson的基本使用方法大全
  • JS+CSS实现数字滚动
  • Laravel 实践之路: 数据库迁移与数据填充
  • PHP面试之三:MySQL数据库
  • Redis提升并发能力 | 从0开始构建SpringCloud微服务(2)
  • Sublime Text 2/3 绑定Eclipse快捷键
  • VUE es6技巧写法(持续更新中~~~)
  • 力扣(LeetCode)357
  • 聊聊flink的BlobWriter
  • 王永庆:技术创新改变教育未来
  • 微信开源mars源码分析1—上层samples分析
  • 小程序 setData 学问多
  • 小而合理的前端理论:rscss和rsjs
  • 小白应该如何快速入门阿里云服务器,新手使用ECS的方法 ...
  • ​flutter 代码混淆
  • #include
  • #pragma once
  • (1)SpringCloud 整合Python
  • (C++)八皇后问题
  • (Java)【深基9.例1】选举学生会
  • (一)Linux+Windows下安装ffmpeg
  • (一)使用Mybatis实现在student数据库中插入一个学生信息
  • (转)IIS6 ASP 0251超过响应缓冲区限制错误的解决方法
  • (转)Sublime Text3配置Lua运行环境
  • (转)使用VMware vSphere标准交换机设置网络连接
  • (转)项目管理杂谈-我所期望的新人
  • . Flume面试题
  • .Net Core/.Net6/.Net8 ,启动配置/Program.cs 配置
  • .NET Framework 3.5中序列化成JSON数据及JSON数据的反序列化,以及jQuery的调用JSON
  • .NET HttpWebRequest、WebClient、HttpClient
  • .Net 垃圾回收机制原理(二)
  • .NET/C# 阻止屏幕关闭,阻止系统进入睡眠状态
  • .netcore 如何获取系统中所有session_ASP.NET Core如何解决分布式Session一致性问题
  • /usr/lib/mysql/plugin权限_给数据库增加密码策略遇到的权限问题
  • [ 隧道技术 ] 反弹shell的集中常见方式(二)bash反弹shell
  • [04] Android逐帧动画(一)
  • [AAuto]给百宝箱增加娱乐功能
  • [ASP.NET 控件实作 Day7] 设定工具箱的控件图标
  • [BJDCTF2020]The mystery of ip