Python 迭代器与生成器

Stella981
• 阅读 488

python 迭代器与生成器


说到python迭代器,首先要明确两个概念:IterableIterator,这两个概念还有Generator都是定义在collections模块里的。

Iterable意为“可迭代的(对象)”,包括如下两种:

1、实现了__getitem__(self,index)方法的对象

这类对象用for关键字迭代时,索引从0开始递增,每次+1, 直到__getitem__方法抛出IndexError或者StopIteration错误则停止迭代。

2、实现了__iter__(self)方法的对象

约定:返回的对象必须包含__next__(self)方法, 用for关键字迭代时,__next__方法抛出StopIteration错误则停止迭代。

一般来说,list、tuple都是实现了__getitem__(self,index)方法因而可迭代,而dict则是实现了__iter__(self)而可迭代。可迭代对象都可以被for关键字迭代,也可以用内建函数iter转化为迭代器对象。

Iterator即迭代器对象。迭代器和可迭代对象不同。迭代器的要求是:

1、实现了__next__(self)方法 2、实现了__iter__(self)方法

约定:__iter__(self)方法应返回自身

以上的约定并非强制的,即使不遵守也可以通过isinstance的检查,但为避免错误,建议编写代码时遵守约定。

Generator即生成器,生成器都实现了迭代器协议,因此所有的生成器都是迭代器。生成器除了迭代器的两个方法之外,还要包含如下方法:

  1. send(self,value)方法,用于向生成器发送值;
  1. throw(self,error)方法,用于向生成器抛入错误;
  2. close(self)方法,用于关闭生成器;

如果一个迭代器具有上述三个方法,就被识别为生成器。

生成器的约定:

  1. send方法用于向生成器发送一个值,一个生成器接受的第一个值必须是None,即一个生成器第一次调用必须是__next__方法,该方法等价于send(None)
  1. close方法的效果是在生成器中产生一个GeneratorExit异常,异常的作用是触发生成器中可能的try...except...finally的finally块,或者with block的__exit__方法。
  2. throw方法的作用是向生成器中抛入异常。可以抛入GeneratorExit异常。也可以抛入其他异常。生成器可以利用不同异常进行不同的善后处理,但不应捕获GeneratorExit异常。

生成器当然可以使用class实现Generator协议的各个方法和约定来实现。但通常,我们使用如下两个方法来创建生成器:

  1. 生成器解析式,类似列表解析,但将中括号替换成小括号。
  1. 使用yield来创建生成器。如果一个函数内部使用了yield,该函数执行的结果就是一个生成器。

关于后者,有如下知识点:

  1. 关键字yield的语法是yield x或者y=yield x,其操作是先将x输出,然后调用send方法或者__next__方法后继续从yield后执行。
  1. 如果调用send方法,yield会接收传递的值并赋给y;如果调用__next__方法,yield接收到的值为None。
  2. 调用throw方法可以将异常抛入生成器内,异常从yield处进入生成器,随后就进入异常处理途径,被捕获处理或者继续向外抛出。GeneratorExit异常不应被处理。
  3. 调用close方法生成的GeneratorExit异常也是从yield处出现的。close方法会在最后捕获该异常,不会抛出该异常到外部。
  4. 生成器代码块里的return语句的返回值将作为StopIteration异常类的构造函数的参数来生成该异常,捕获该异常,其value字段即为返回值。

附注:协程旧语法yield from的知识点

  1. 关键字yield from的语法为x=yield from B,其中B为一个生成器。生成的协程函数(设其为A)同样满足生成器协议。
  1. 所有通过send方法发送到A的数据,如果值为None则调用B的__next__方法;否则将调用B的send方法将值直接传递给B。
  2. 如果调用A的close方法,则B的close方法也会被调用。
  3. 如果通过A的throw方法抛入GeneratorExit异常,会调用B的close方法,然后再从A的yield from处抛出该异常。
  4. 如果通过A的throw方法抛入非GeneratorExit的异常,会调用B的throw方法将异常直接抛入B中。
  5. 如果B抛出StopIteration异常,该异常的value字段值将赋给x,而A将从yield from后继续执行。
  6. 如果B抛出非StopIteration的异常,则该异常会从yield from处抛入A中。

yield from目前基本不被用作协程之间的交流了,现在都用async...await语法来实现协程。但是yield from仍然有用,也就是可以用作生成器的修饰,即增加生成器的上下文处理。

点赞
收藏
评论区
推荐文章
blmius blmius
2年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
Jacquelyn38 Jacquelyn38
2年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
Stella981 Stella981
2年前
Python3:sqlalchemy对mysql数据库操作,非sql语句
Python3:sqlalchemy对mysql数据库操作,非sql语句python3authorlizmdatetime2018020110:00:00coding:utf8'''
Stella981 Stella981
2年前
Python之time模块的时间戳、时间字符串格式化与转换
Python处理时间和时间戳的内置模块就有time,和datetime两个,本文先说time模块。关于时间戳的几个概念时间戳,根据1970年1月1日00:00:00开始按秒计算的偏移量。时间元组(struct_time),包含9个元素。 time.struct_time(tm_y
Wesley13 Wesley13
2年前
00:Java简单了解
浅谈Java之概述Java是SUN(StanfordUniversityNetwork),斯坦福大学网络公司)1995年推出的一门高级编程语言。Java是一种面向Internet的编程语言。随着Java技术在web方面的不断成熟,已经成为Web应用程序的首选开发语言。Java是简单易学,完全面向对象,安全可靠,与平台无关的编程语言。
Stella981 Stella981
2年前
Django中Admin中的一些参数配置
设置在列表中显示的字段,id为django模型默认的主键list_display('id','name','sex','profession','email','qq','phone','status','create_time')设置在列表可编辑字段list_editable
Stella981 Stella981
2年前
OpenCV访问像素点
三种方法迭代器创建一个Mat::Iterator对象it,通过itMat::begin()来的到迭代首地址,递增迭代器知道itMat::end()结束迭代;while(it!Scr.end<Vec3b()){//(it)00;//蓝色通道置零;
Wesley13 Wesley13
2年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
Python进阶者 Python进阶者
3个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这