恒美微站
首页
关于我们
建站服务
主题模板
案例展示
资讯中心
联系我们
重新认识生成器generator
首页
资讯中心
/
重新认识生成器generator
重新认识生成器generator
发布时间:2026/9/4 18:53:34
基本用法我们清楚, 函数体之中含有yield关键字的函数并非是一个平常的函数, 这一种函数被称作生成器, 通常是用来进行循环处理结构的, 要是应用得恰当的话能够极大程度地优化内存使用效率, 比如说, 去设计一个函数, 将文件打开并且把每一行都转变成大写之后还返还回来:123456defread_file_upper(path):lines []withopen(path)asf:forlineinf:lines.append(line.upper())returnlines这个版本的函数于内部构建了一个 list 对象, 此对象是用来存放转换结果的, for 循环会对文件当中的每一行进行遍历, 把每一行转变成大写之后追加至列表里, 如此这般, 文件里的每一行都得保存在列表中, 而要是文件规模很大, 那么内存开销的情况便可想而知了。我们能够借助yield关键字, 把函数转变为生成器版本, 函数主体的逻辑不存在任何改变, 仅仅是将每行数据的处理结果借助yield逐个予以返回, 并非是在收集到list对象之后再进行返还。1234defiter_file_upper(path):withopen(path)asf:forlineinf:yieldline.upper()要是当下存在一个文本文件data.txt, 其里面涵盖着如下内容:hello, world life is short, use python my wechat id is: coding-fan bye用 生成器我们可以这样对它进行处理123456forlineiniter_file_upper(text.txt): ...print(line.strip())HELLO,WORLDLIFEISSHORT,USEPYTHONMYWECHATIDIS:CODING-FANBYE大致来说, 生成器用法跟函数是差不多一样的, 然而它不会一下子就把文件里所有的数据行都给拿住, 反而是一行一行地去做处理一个一个地返回, 如此一来, 便能把内存的使用量降低到最低限度。行为观察那么生成器为什么会有这样的奇效呢我们接着观察123giter_file_upper(text.txt) ggeneratorobjectiter_file_upperat0x103becd68经过我们进行调用之后, 所得到的是一个生成器对象, 并非是文件处理的结果, 在这个时候, 它还尚未开始执行。在咱们调用 next 函数以便从生成器那里接收紧接着的那个数据之际, 便会着手开始执行, 而后在 yield 所处的那个位置停下来, 并且还会把处于第一行的处理之后所得到的结果返还给咱们:12next(g)HELLO, WORLD\n在这个时候, 生成器所处的状态是暂停, 要是没有我们所给出的指令, 那么它是不会紧接着去处理第二行数据的。当我们再度去执行next函数之时, 生成器又一次恢复进行执行, 去处理下一行的数据, 并且在yield此处又一次暂停:12next(g)LIFE IS SHORT, USE PYTHON\n生成器记住了自身的执行进度, 每当调用next函数时, 它总会去处理并产出下一个数据, 根本无需我们费尽心思去留意操心:1234next(g)MY WECHAT ID IS: CODING-FAN\nnext(g)BYE\n在那代码逻辑执行完结以后, 它会朝着next抛出一个异常, 利用这样的方式去告知调用者它已然结束了:1234next(g)Traceback(mostrecentcalllast):File,line1,inmoduleStopIteration所以, 我们能够将其简单地认定为, for-in循环于虚拟机的内部是按照这样的方式来达成的:在经典的线程模型里, 每个线程有着一个独立的执行流, 且仅能执行一项任务。要是一个程序需要同时去处理多个任务, 那么能够借助多进程或者多线程技术。假定一个站点需要同时为多个客户端连接提供服务, 那样可以为每个连接创建一个独立的线程来予以处理。不管是线程, 还是进程, 在进行切换的时候, 都会带来巨大的开销, 比如说用户态与内核态的切换, 执行上下文的保存以及恢复, 还有CPU缓存的刷新等等。所以说, 利用线程或者进程来驱动小任务的执行, 明显不是一个理想的选择。