位置: 编程技术 - 正文

Python中的迭代器与生成器高级用法解析(python迭代器iterator)

编辑:rootadmin

推荐整理分享Python中的迭代器与生成器高级用法解析(python迭代器iterator),希望有所帮助,仅作参考,欢迎阅读内容。

文章相关热门搜索词:python迭代器详解,python迭代器详解,python3迭代器,python里的迭代器,python中的迭代器和生成器,python里的迭代器,python中的迭代器和生成器,python中的迭代器对象,内容如对您有帮助,希望把文章链接给更多的朋友!

迭代器

迭代器是依附于迭代协议的对象——基本意味它有一个next方法(method),当调用时,返回序列中的下一个项目。当无项目可返回时,引发(raise)StopIteration异常。

迭代对象允许一次循环。它保留单次迭代的状态(位置),或从另一个角度讲,每次循环序列都需要一个迭代对象。这意味我们可以同时迭代同一个序列不只一次。将迭代逻辑和序列分离使我们有更多的迭代方式。

调用一个容器(container)的__iter__方法创建迭代对象是掌握迭代器最直接的方式。iter函数为我们节约一些按键。

当在循环中使用时,StopIteration被接受并停止循环。但通过显式引发(invocation),我们看到一旦迭代器元素被耗尽,存取它将引发异常。

使用for...in循环也使用__iter__方法。这允许我们透明地开始对一个序列迭代。但是如果我们已经有一个迭代器,我们想在for循环中能同样地使用它们。为了实现这点,迭代器除了next还有一个方法__iter__来返回迭代器自身(self)。

Python中对迭代器的支持无处不在:标准库中的所有序列和无序容器都支持。这个概念也被拓展到其它东西:例如file对象支持行的迭代。

file自身就是迭代器,它的__iter__方法并不创建一个单独的对象:仅仅单线程的顺序读取被允许。

生成表达式第二种创建迭代对象的方式是通过 生成表达式(generator expression) ,列表推导(list comprehension)的基础。为了增加清晰度,生成表达式总是封装在括号或表达式中。如果使用圆括号,则创建了一个生成迭代器(generator iterator)。如果是方括号,这一过程被‘短路'我们获得一个列表list。

在Python 2.7和 3.x中列表表达式语法被扩展到 字典和集合表达式。一个集合set当生成表达式是被大括号封装时被创建。一个字典dict在表达式包含key:value形式的键值对时被创建:

如果您不幸身陷古老的Python版本中,这个语法有点糟:

生成表达式相当简单,不用多说。只有一个陷阱值得提及:在版本小于3的Python中索引变量(i)会泄漏。

生成器

生成器是产生一列结果而不是单一值的函数。

第三种创建迭代对象的方式是调用生成器函数。一个 生成器(generator) 是包含关键字yield的函数。值得注意,仅仅是这个关键字的出现完全改变了函数的本质:yield语句不必引发(invoke),甚至不必可接触。但让函数变成了生成器。当一个函数被调用时,其中的指令被执行。而当一个生成器被调用时,执行在其中第一条指令之前停止。生成器的调用创建依附于迭代协议的生成器对象。就像常规函数一样,允许并发和递归调用。当next被调用时,函数执行到第一个yield。每次遇到yield语句获得一个作为next返回的值,在yield语句执行后,函数的执行又被停止。

让我们遍历单个生成器函数调用的整个历程。

Python中的迭代器与生成器高级用法解析(python迭代器iterator)

相比常规函数中执行f()立即让print执行,gen不执行任何函数体中语句就被赋值。只有当gen.next()被next调用,直到第一个yield部分的语句才被执行。第二个语句打印-- middle --并在遇到第二个yield时停止执行。第三个next打印-- finished --并且到函数末尾,因为没有yield,引发了异常。

当函数yield之后控制返回给调用者后发生了什么?每个生成器的状态被存储在生成器对象中。从这点看生成器函数,好像它是运行在单独的线程,但这仅仅是假象:执行是严格单线程的,但解释器保留和存储在下一个值请求之间的状态。

为何生成器有用?正如关于迭代器这部分强调的,生成器函数只是创建迭代对象的又一种方式。一切能被yield语句完成的东西也能被next方法完成。然而,使用函数让解释器魔力般地创建迭代器有优势。一个函数可以比需要next和__iter__方法的类定义短很多。更重要的是,相比不得不对迭代对象在连续next调用之间传递的实例(instance)属性来说,生成器的作者能更简单的理解局限在局部变量中的语句。

还有问题是为何迭代器有用?当一个迭代器用来驱动循环,循环变得简单。迭代器代码初始化状态,决定是否循环结束,并且找到下一个被提取到不同地方的值。这凸显了循环体——最值得关注的部分。除此之外,可以在其它地方重用迭代器代码。

双向通信每个yield语句将一个值传递给调用者。这就是为何PEP 引入生成器(在Python2.2中实现)。但是相反方向的通信也很有用。一个明显的方式是一些外部(extern)语句,或者全局变量或共享可变对象。通过将先前无聊的yield语句变成表达式,直接通信因PEP 成为现实(在2.5中实现)。当生成器在yield语句之后恢复执行时,调用者可以对生成器对象调用一个方法,或者传递一个值 给 生成器,然后通过yield语句返回,或者通过一个不同的方法向生成器注入异常。

第一个新方法是send(value),类似于next(),但是将value传递进作为yield表达式值的生成器中。事实上,g.next()和g.send(None)是等效的。

第二个新方法是throw(type, value=None, traceback=None),等效于在yield语句处

不像raise(从执行点立即引发异常),throw()首先恢复生成器,然后仅仅引发异常。选用单次throw就是因为它意味着把异常放到其它位置,并且在其它语言中与异常有关。

当生成器中的异常被引发时发生什么?它可以或者显式引发,当执行某些语句时可以通过throw()方法注入到yield语句中。任一情况中,异常都以标准方式传播:它可以被except和finally捕获,或者造成生成器的中止并传递给调用者。

因完整性缘故,值得提及生成器迭代器也有close()方法,该方法被用来让本可以提供更多值的生成器立即中止。它用生成器的__del__方法销毁保留生成器状态的对象。

让我们定义一个只打印出通过send和throw方法所传递东西的生成器。

注意: next还是__next__&#;

在Python 2.x中,接受下一个值的迭代器方法是next,它通过全局函数next显式调用,意即它应该调用__next__。就像全局函数iter调用__iter__。这种不一致在Python 3.x中被修复,it.next变成了it.__next__。对于其它生成器方法——send和throw情况更加复杂,因为它们不被解释器隐式调用。然而,有建议语法扩展让continue带一个将被传递给循环迭代器中send的参数。如果这个扩展被接受,可能gen.send会变成gen.__send__。最后一个生成器方法close显然被不正确的命名了,因为它已经被隐式调用。

链式生成器注意: 这是PEP 的预览(还未被实现,但已经被Python3.3接受)

比如说我们正写一个生成器,我们想要yield一个第二个生成器——一个子生成器(subgenerator)——生成的数。如果仅考虑产生(yield)的值,通过循环可以不费力的完成:

然而,如果子生成器需要调用send()、throw()和close()和调用者适当交互的情况下,事情就复杂了。yield语句不得不通过类似于前一章节部分定义的try...except...finally结构来保证“调试”生成器函数。这种代码在PEP 中提供,现在足够拿出将在Python 3.3中引入的新语法了:

像上面的显式循环调用一样,重复从some_other_generator中产生值直到没有值可以产生,但是仍然向子生成器转发send、throw和close。

深入理解Python中装饰器的用法 因为函数或类都是对象,它们也能被四处传递。它们又是可变对象,可以被更改。在函数或类对象创建后但绑定到名字前更改之的行为为装饰(decorator)。

Python中线程的MQ消息队列实现以及消息队列的优点解析 消息队列是在消息的传输过程中保存消息的容器。消息队列管理器在将消息从它的源中继到它的目标时充当中间人。队列的主要目的是提供路由并保证

Python的消息队列包SnakeMQ使用初探 一、关于snakemq的官方介绍SnakeMQ的GitHub项目页:

标签: python迭代器iterator

本文链接地址:https://www.jiuchutong.com/biancheng/386978.html 转载请保留说明!

上一篇:Python设计足球联赛赛程表程序的思路与简单实现示例(python画足球)

下一篇:深入理解Python中装饰器的用法(python深入浅出)

  • 个人应纳税所得额20万交多少税
  • 一般纳税人出租不动产增值税税率
  • 没有销项购买税金税盘如何做账
  • 加计抵扣进项税额政策2022
  • 营业执照办理税务登记需要什么资料
  • 农产品抵扣计算题
  • 小规模可以开红网吗
  • 期初数调整的分录怎么做
  • 冲销以前年度营业外支出
  • 2019所得税新政策
  • 第一季度亏损第=季度盈利但累计还是亏损要交所得税吗?
  • 小微企业免税计入什么科目
  • 建筑业预缴税款是什么意思
  • 复印的原始凭证可以作为记账依据吗
  • 预缴增值税时可抵扣吗
  • 企业会计制准下增值税科目的核算
  • 员工劳动保险赔多少钱
  • 事业单位库存物品
  • 筹建期发生的费用
  • 企业税收滞纳金计入什么科目
  • 资产负债表货币资金与现金流量表的关系
  • 多层股权结构设计控制法
  • 简易计税是否可以开增值税专用发票
  • 案例分析工程发票进项高于销项怎么抵扣?
  • 利润表反映了哪些情况
  • 期货盈利需要交什么税
  • 以实物投资的税种有哪些
  • 银行没有流水怎么开证明
  • 无票收入确认收入
  • 关联企业借款利息税前扣除
  • windows无法连接到打印机指定的网络名不再可用
  • 王者荣耀中孙尚香怎么玩
  • 销售折让负数发票如何入账
  • 政府补助开票怎么申报增值税
  • 分级核算下的建议怎么写
  • 增值税价外费用如何开票
  • bearshare.exe进程安全吗 bearshare是什么进程
  • 个人之间股权转让印花税怎么交
  • npm无法将npm项识别为
  • php面向对象的理解
  • 长期股权投资
  • 购入固定资产应该怎么做账
  • 发票货物或应税劳务名称怎么填写
  • 公司承担员工的费用,员工违规吗
  • sql server使用sql语句
  • 什么是增值?
  • 增值税出口免税不退税
  • sqlserver2008密码要求
  • sql server 2008使用说明
  • 新成立企业多长时间可以销售小微企业
  • 收员工伙食费会计分录
  • 固定资产盘亏如何做账务处理
  • 制造费用怎么写
  • 过桥贷款有什么风险
  • 工会经费是不是税费
  • 公司与公司之间可以借款吗
  • 财务费用具体包括
  • 企业支付境外佣金要交税吗?
  • 公司建账初期做账怎么做
  • 开发票系统税号0和o怎么区别?
  • 如何在境外银行开户
  • 当你感觉到你的win2000运行速度明显减慢
  • windows xp和windows 2000
  • 怎么禁止p2p下载器
  • vmmem进程是什么
  • centos启动卡在了启动界面
  • 安装ubuntu不支持nvidia显卡
  • register.exe - register进程有什么用.是什么意思
  • win10快速隐藏窗口
  • js数组常用的方法及用法
  • cocos onload
  • 第三章之一、使用二手设备降低生产成本读后感
  • JavaScript事件处理的方式(三种)
  • android内存分析显示
  • python常用的库
  • Forward Render VS Deferred Rendering
  • 退伍军人买车需要摇号吗
  • 银行代扣流程
  • 设备租赁增值税怎么抵扣
  • 医院要交税吗
  • 免责声明:网站部分图片文字素材来源于网络,如有侵权,请及时告知,我们会第一时间删除,谢谢! 邮箱:opceo@qq.com

    鄂ICP备2023003026号

    网站地图: 企业信息 工商信息 财税知识 网络常识 编程技术

    友情链接: 武汉网站建设