对Python生成器的理解

2023-11-05

下午看了一点生成器的内容,这部分算是python的基础吧。所以我就不放在我的进阶系列了。正好吃饱饭没事做,就来写写我对生成器的一点浅薄理解吧。 ——无聊的前言


一.为什么要有生成器

秉着先问为什么,再问怎么做的原则,我们来看看为什么python会添加生成器这个功能。

python在数据科学领域可以说是很火。我想有一部分的功劳就是它的生成器了吧。

我们知道我们可以用列表储存数据,可是当我们的数据特别大的时候建立一个列表的储存数据就会很占内存的。这时生成器就派上用场了。它可以说是一个不怎么占计算机资源的一种方法。


二.简单的生成器

我们可以用列表推导(生成式)来初始化一个列表:

list5 = [x for x in range(5)]
print(list5)   #output:[0, 1, 2, 3, 4]

我们用类似的方式来生成一个生成器,只不过我们这次将上面的[ ]换成( ):

gen = (x for x in range(5))
print(gen) 
#output: <generator object <genexpr> at 0x0000000000AA20F8>

看到上面print(gen) 并不是直接输出结果,而是告诉我们这是一个生成器。那么我们要怎么调用这个gen呢。
有两种方式:
第一种:

for item in gen:
    print(item)
#output:
0
1
2
3
4

第二种:

print(next(gen))#output:0
print(next(gen))#output:1
print(next(gen))#output:2
print(next(gen))#output:3
print(next(gen))#output:4
print(next(gen))#output:Traceback (most recent call last):StopIteration

好了。现在可以考虑下背后的原理是什么了。
从第一个用for的调用方式我们可以知道生成器是可迭代的。更准确的说法是他就是个迭代器。
我们可以验证一下:

from collections import Iterable, Iterator
print(isinstance(gen, Iterable))#output:True
print(isinstance(gen, Iterator))#output:True

str,list,tuple,dict,set这些都是可迭代的,就是可用for来访问里面的每一个元素。但他们并不是迭代器。

那什么是迭代器?
我们可以理解为我们平时做一件事的步骤。

比如我们泡茶:
首先,得去煮水。
然后,拿出茶具,和茶叶
接着,水开了,就开始泡茶
最后,就是品茶了。

假如我们定义了一个泡茶的函数(迭代器),然后将泡茶步骤的方法封装进这个函数。每一次调用这个函数就返回一个步骤,并保存好当前执行到哪个状态。如果中途有事,比如我们执行到步骤二的时候突然去接了个电话,回来调用这个函数就会得到步骤三(水开了,就开始泡茶),也就是状态保存好了。我们可以执行这个泡茶函数直到调用完所有步骤为止。
定义一个方法,这个方法是一步步执行的,并能保存状态,这就是迭代器。

回到上面上面第二种访问方法中,到第六个print(next(gen))时,系统告诉我们Traceback (most recent call last): StopIteration。也就是gen迭代到最后了,无法继续迭代了。

而生成器本身就是一个迭代器
我们在内部封装好了算法,并规定好在某个条件下就返回一个结果给调用者。(x for x in range(5))就是这样子实现的,并不是实现了(0,1,2,3,4)然后在一个个迭代出来,而是逐个生成。这就是为什么next(gen)可以作用了。


三.应用

1.前面说到生成器生成大量数据的时候可帮助系统节省内存。真的是这样吗?通过下面的代码感受下:

代码里面会运用到装饰器的原理,看不懂没关系后文会解释有什么作用。当然想了解的可以看我另一篇博文:Python进阶(四):浅析装饰器(decorator)@

import time

def get_time(func):
    def wraper(*args, **kwargs):
        start_time = time.time()
        result = func(*args, **kwargs)
        end_time = time.time()
        print("Spend:", end_time - start_time)
        return result
    return wraper

@get_time
def _list(n):
    l1 = [list(range(n)) for i in range(n)]
    del ge


@get_time
def _generator(n):
    ge = (tuple(range(n)) for i in range(n))
    del t1

_list(1000)
_generator(1000)

哈哈,有人实在看不懂的话可以看下面的代码,与上面等效的

题外话:其实上面那个get_time函数是我自己平常经常要用到的一个功能。我把它写到一个我的工具包里了(造轮子),就是如果我想看看一段函数的执行时间(测试效率),就掉用这个包里的get_time装饰器,装饰一下就好了。所以建议大家如果发现有个功能经常要用到的话可以尝试下自己造轮子。这里我就直接贴上代码了

import time

def _list(n):
    l1 = [list(range(n)) for i in range(n)]
    del l1

def _generator(n):
    ge = (tuple(range(n)) for i in range(n))
    del ge

start_time = time.time()
_list(1000)
end_time = time.time()
print("Spend:",end_time - start_time)

start_time = time.time()
_generator(1000)
end_time = time.time()
print("Spend:",end_time - start_time)

好了,运行代码我们可以看到:

Spend: 0.04300236701965332
Spend: 0.0

分析下就可以知道,列表是将0-999都生成后放进一个列表里面了,所以用得时间比较多。
而生成器只是封装了算法,每次调用在去调用算法,这样做就可以做到节省内存了。

2.yield 关键词

好吧,前面只告诉我们用( )来创建一个生成器。如果我们想定义一个自己的生成器函数怎么办?用return好像不行。没关系,python有yield的关键词。其作用和return的功能差不多,就是返回一个值给调用者,只不过有yield的函数返回值后函数依然保持调用yield时的状态,当下次调用的时候,在原先的基础上继续执行代码,直到遇到下一个yield或者满足结束条件结束函数为止。

一个简单的例子:

def test():
    yield 1
    yield 2
    yield 3
t = test()

print(next(t))#output:1
print(next(t))#output:1
print(next(t))#output:1
print(next(t))#output:Traceback (most recent call last):StopIteration

好像并没啥卵用啊!骚年,存在即合理,python有生成器不是没有道理的。数学中有很多算法是无限穷举的(比如自然数),我们不可能一一穷举出来,所以生成器就可以帮助我们。
举个例子:杨辉三角。
这里写图片描述
这就是一个无限穷举的,我们可以将他的算法封装成生成器,需要的时候去生成就好,这样就不会占用大量的电脑内存资源。
下面给出代码:

def triangle():
    _list, new_list = [], []
    while True:
        length = len(_list)
        if length == 0:
            new_list.append(1)
        else:
            for times in range(length + 1):
                if times == 0:
                    new_list.append(1)
                elif times == length:
                    new_list.append(1)
                else:
                    temp = _list[times - 1] + _list[times]
                    new_list.append(temp)
        yield new_list #返回值,然后挂起函数,等待下一次调用
        _list = new_list.copy()#调用后会继续执行下去
        new_list.clear()

n = 0
for result in triangle():
    n += 1
    print(result)
    if n == 10:
        break

结果:

[1]
[1, 1]
[1, 2, 1]
[1, 3, 3, 1]
[1, 4, 6, 4, 1]
[1, 5, 10, 10, 5, 1]
[1, 6, 15, 20, 15, 6, 1]
[1, 7, 21, 35, 35, 21, 7, 1]
[1, 8, 28, 56, 70, 56, 28, 8, 1]
[1, 9, 36, 84, 126, 126, 84, 36, 9, 1]

好了,觉得写得好可以关注微信公众号:
这里写图片描述

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

对Python生成器的理解 的相关文章

  • 如何查看Databricks中的所有数据库和表

    我想列出 Azure Databricks 中每个数据库中的所有表 所以我希望输出看起来像这样 Database Table name Database1 Table 1 Database1 Table 2 Database1 Table
  • 使用 pythonbrew 编译 Python 3.2 和 2.7 时出现问题

    我正在尝试使用构建多个版本的 python蟒蛇酿造 http pypi python org pypi pythonbrew 0 7 3 但我遇到了一些测试失败 这是在运行的虚拟机上 Ubuntu 8 04 32 位 当我使用时会发生这种情
  • 使用 psycopg2 在 python 中执行查询时出现“编程错误:语法错误位于或附近”

    我正在运行 Python v 2 7 和 psycopg2 v 2 5 我有一个 postgresql 数据库函数 它将 SQL 查询作为文本字段返回 我使用以下代码来调用该函数并从文本字段中提取查询 cur2 execute SELECT
  • 没有名为 crypto.cipher 的模块

    我现在正在尝试加密一段时间 我最近得到了这个基于 python 的密码器 名为PythonCrypter https github com jbertman PythonCrypter 我对 Python 相当陌生 当我尝试通过终端打开 C
  • Python 的键盘中断不会中止 Rust 函数 (PyO3)

    我有一个使用 PyO3 用 Rust 编写的 Python 库 它涉及一些昂贵的计算 单个函数调用最多需要 10 分钟 从 Python 调用时如何中止执行 Ctrl C 好像只有执行结束后才会处理 所以本质上没什么用 最小可重现示例 Ca
  • 将数据从 python pandas 数据框导出或写入 MS Access 表

    我正在尝试将数据从 python pandas 数据框导出到现有的 MS Access 表 我想用已更新的数据替换 MS Access 表 在 python 中 我尝试使用 pandas to sql 但收到错误消息 我觉得很奇怪 使用 p
  • 使 django 服务器可以在 LAN 中访问

    我已经安装了Django服务器 可以如下访问 http localhost 8000 get sms http 127 0 0 1 8000 get sms 假设我的IP是x x x x 当我这样做时 从同一网络下的另一台电脑 my ip
  • 通过最小元素比较对 5 个元素进行排序

    我必须在 python 中使用元素之间的最小比较次数来建模对 5 个元素的列表进行排序的执行计划 除此之外 复杂性是无关紧要的 结果是一个对的列表 表示在另一时间对列表进行排序所需的比较 我知道有一种算法可以通过 7 次比较 总是在元素之间
  • 使用带有关键字参数的 map() 函数

    这是我尝试使用的循环map功能于 volume ids 1 2 3 4 5 ip 172 12 13 122 for volume id in volume ids my function volume id ip ip 我有办法做到这一点
  • 是否可以忽略一行的pyright检查?

    我需要忽略一行的pyright 检查 有什么特别的评论吗 def create slog group SLogGroup data Optional dict None SLog insert one SLog group group da
  • Python pickle:腌制对象不等于源对象

    我认为这是预期的行为 但想检查一下 也许找出原因 因为我所做的研究结果是空白 我有一个函数可以提取数据 创建自定义类的新实例 然后将其附加到列表中 该类仅包含变量 然后 我使用协议 2 作为二进制文件将该列表腌制到文件中 稍后我重新运行脚本
  • 如何加速Python中的N维区间树?

    考虑以下问题 给定一组n间隔和一组m浮点数 对于每个浮点数 确定包含该浮点数的区间子集 这个问题已经通过构建一个解决区间树 https en wikipedia org wiki Interval tree 或称为范围树或线段树 已经针对一
  • 如何在ipywidget按钮中显示全文?

    我正在创建一个ipywidget带有一些文本的按钮 但按钮中未显示全文 我使用的代码如下 import ipywidgets as widgets from IPython display import display button wid
  • 如何在Python中对类别进行加权随机抽样

    给定一个元组列表 其中每个元组都包含一个概率和一个项目 我想根据其概率对项目进行采样 例如 给出列表 3 a 4 b 3 c 我想在 40 的时间内对 b 进行采样 在 python 中执行此操作的规范方法是什么 我查看了 random 模
  • Fabric env.roledefs 未按预期运行

    On the 面料网站 http docs fabfile org en 1 10 usage execution html 给出这个例子 from fabric api import env env roledefs web hosts
  • 如何在 Python 中追加到 JSON 文件?

    我有一个 JSON 文件 其中包含 67790 1 kwh 319 4 现在我创建一个字典a dict我需要将其附加到 JSON 文件中 我尝试了这段代码 with open DATA FILENAME a as f json obj js
  • 有人用过 Dabo 做过中型项目吗? [关闭]

    Closed 这个问题是基于意见的 help closed questions 目前不接受答案 我们正处于一个新的 ERP 风格的客户端 服务器应用程序的开始阶段 该应用程序是作为 Python 富客户端开发的 我们目前正在评估 Dabo
  • Conda SafetyError:文件大小不正确

    使用创建 Conda 环境时conda create n env name python 3 6 我收到以下警告 Preparing transaction done Verifying transaction SafetyError Th
  • Scrapy:如何使用元在方法之间传递项目

    我是 scrapy 和 python 的新手 我试图将 parse quotes 中的项目 item author 传递给下一个解析方法 parse bio 我尝试了 request meta 和 response meta 方法 如 sc
  • 在 Qt 中自动调整标签文本大小 - 奇怪的行为

    在 Qt 中 我有一个复合小部件 它由排列在 QBoxLayouts 内的多个 QLabels 组成 当小部件调整大小时 我希望标签文本缩放以填充标签区域 并且我已经在 resizeEvent 中实现了文本大小的调整 这可行 但似乎发生了某

随机推荐

  • Qt程序打包发布记录使用windeployqt工具

    Qt 官方开发环境使用的动态链接库方式 在发布生成的exe程序时 需要复制一大堆 dll 如果自己去复制dll 很可能丢三落四 导致exe在别的电脑里无法正常运行 因此 Qt 官方开发环境里自带了一个工具 windeployqt exe 首
  • Vue3和Vue2的区别

    目录 前言 概览 一 新特性 二 差异 详情 一 vue3新特性 1 组合式API setup 2 ref创建响应式数据 3 Teleport 传送门 4 多根节点 5 style中使用变量 二 区别 1 v if和v for的优先级 2
  • ios 获取服务器js文件是否存在,使用js的XMLHttpRequest对象,在ios中获取服务器上的txt,经常失败…...

    但是在pc上还没发现过失败 ios上失败时候的症状是 XMLHttpRequest readyState到2之后就没有东西了 以下是代码 ajax video music20 0music list txt function data if
  • 使用pygame.display.set_mode()函数的时候,遇到TypeError: argument 1 must be 2-item sequence, not int 问题

    screen pygame display set mode ai settings screen width ai settings screen height TypeError argument 1 must be 2 item se
  • 动画制作如何选择动作捕捉动画制作服务

    近日 长宁ART PARK 大融城迎来了首位虚拟代言人 光艺 拥有着极具感染力的笑容 数字人形象辨识度极高 在裸眼3D巨屏中 为市民带来虚实交互体验 而这种数字人动画的背后 大多以动作捕捉动画制作技术为主 素材源于网络 在动画制作中 想要全
  • 手把手教你封装高德地图组件

    背景 最近的一个项目中需要用到地图功能 经过一番调研 决定对于国内用户采用高德地图API 对于国外用户采用谷歌地图API 本期讲讲如何在vue项目中封装高德地图组件 下一期讲述如何封装谷歌地图组件 本次组件所满足的大致需求是 传入经纬度数据
  • 运行项目报错 proxy error: could not proxy request...

    今天跑项目的时候遇到一个问题 早上跑的时候还好好的 午休完起来一看 页面报错了 弹窗提示 proxy error could not proxy request from 我本地 to 目标地址 终端报错 Proxy error Could
  • android设备之间屏幕共享

    近期公司在开发一款android的设备把屏幕投射到手机上 同一时候手机还能够触控 键盘操作 这样 就达到了屏幕共享的目的 思考了一下 主要思路 1 将截图所获取的位图用ffmpeg编码成视频流 2 将视频流用live555进行流媒体分发 手
  • 复变函数与积分变换

    复变函数与积分变换 一 拉普拉斯变换 1 拉氏变换的性质 a 线性性质 b 相似性质 c 微分性质 例子 例子 拉式变换 象函数的微分性质 例子 例子 积分性质 象函数的积分性质 例子 例子 延迟性质 位移性质 拉氏变换的应用 一 拉普拉斯
  • keytool命令来生成证书缺少MD5

  • Stream篇(四)

    FileStream 如何去理解FileStream 通过前3章的学习相信大家对于Stream已经有一定的了解 但是又如何去理解FileStream呢 请看下图 我们磁盘的中任何文件都是通过2进制组成 最为直观的便是记事本了 当我们新建一个
  • SpringMVC使用Ajax请求返回中文乱码

    使用 ResponseBody标记返回参数 当类型为String时 返回的中文可能会出现乱码问题 而当返回值是Map
  • QTableWidget设置代理 添加QCombox

    一 实现功能 向QTableWidget上添加QCombox 显示效果 双击鼠标才显示Combox组件 如下图所示 未双击效果图 双击效果图 二 向第二列添加combox代码如下 ui tableWidget TestItems gt ve
  • MATLAB入门实战版

    写在前面 众所周知 MATLAB是理工科不可不知的利器 其功能之广 之强可谓万金油 其在科研 数模竞赛 课设等当中有着广泛的用途 甚至也有地方专门开了MATLAB的相关课程 学习MATLAB 对于非计算机专业的理工科选手而言还是很有用的 M
  • main函数,printf函数,和库函数

    main函数 printf函数和库函数 在C语言的入门学习中 细心的朋友们可以发现 一个C语言程序无论有多长 都有一个main函数 而在代码中想要输出结果 就需要用到printf函数 print函数其实就是一个库函数 而库函数有很多 接下来
  • 联想小新Air2020ill版换硬盘及安装Win11详细过程

    打开后盖 先拧下背后的7颗螺丝 红色的可以取下来 绿色的是固定在底板上的 拧松后不能取下来 紫色区域存在一个卡扣 在后文会提到 打开一个缝隙 b站官方拆机视频里的方法https www bilibili com video BV1L7411
  • BASE64转换为图片格式,并上传图片

    基本的把base64 转成图片 将BASE64转换为图片格式 代码 java public static final String JPG jpg public MessageBody
  • Python 爬虫详解

    一 爬虫概述 1 爬虫简介 要对数据进行处理和分析 首先就要拥有数据 在当今这个互联网时代 大量信息以网页作为载体 网页也就成了一个很重要的数据来源 但是 网页的数量非常之多 如果以人工的方式从网页上采集数据 工作量相当巨大 从本章开始就要
  • ElasticSearch IK 安装&使用

    中文分词器 在ES中支持中文分词器非常多 如 smartCN IK 等 推荐的就是 IK分词器 安装IK 开源分词器 Ik 的github GitHub medcl elasticsearch analysis ik The IK Anal
  • 对Python生成器的理解

    下午看了一点生成器的内容 这部分算是python的基础吧 所以我就不放在我的进阶系列了 正好吃饱饭没事做 就来写写我对生成器的一点浅薄理解吧 无聊的前言 一 为什么要有生成器 秉着先问为什么 再问怎么做的原则 我们来看看为什么python会