1、迭代器

for element in [1, 2, 3]:
print(element)
for element in (1, 2, 3):
print(element)
for key in {'one':1, 'two':2}:
print(key)
for char in "123":
print(char)
for line in open("myfile.txt"):
print(line, end='')

在幕后,for 语句会在容器对象(即列表、元组等)上调用 iter()

iter() 返回一个定义了 __next__() 方法的迭代器对象,__next__()将逐一访问容器中的元素。 当元素用尽时,__next__() 将引发 StopIteration 异常来通知终止 for 循环。

可以使用 next() 内置函数来调用 __next__() 方法。这个例子显示了它的运作方式:

>>> s = 'abc'
>>> it = iter(s)
>>> it
<iterator object at 0x00A1DB50>
>>> next(it)
'a'
>>> next(it)
'b'
>>> next(it)
'c'
>>> next(it)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
next(it)
StopIteration

给类添加迭代器行为:定义一个 __iter__() 方法来返回一个带有 __next__() 方法的对象。 如果类已定义了 __next__(),则 __iter__() 可以简单地返回 self:

class Reverse:
"""Iterator for looping over a sequence backwards."""
def __init__(self, data):
self.data = data
self.index = len(data) def __iter__(self):
return self def __next__(self):
if self.index == 0:
raise StopIteration
self.index = self.index - 1
return self.data[self.index]
>>> rev = Reverse('spam')
>>> iter(rev)
<__main__.Reverse object at 0x00A1DB50>
>>> for char in rev:
... print(char)
...
m
a
p
s

2、生成器

2.1、yield 表达式

yield_atom       ::=  "(" yield_expression ")"
yield_expression ::= "yield" [expression_list | "from" expression]

只能在函数定义的内部使用 yield 表达式,在一个函数体内使用 yield 表达式会使这个函数变成一个生成器函数

def gen():  # defines a generator function
yield 123

2.2、简要理解概念

官网原文

generator--生成器

返回一个 generator iterator 的函数。

它看起来很像普通函数,不同点在于其包含 yield 表达式,以便产生一系列值供给 for 循环使用或是通过 next() 函数逐一获取。

通常是指生成器函数,但在某些情况下也可能是指生成器迭代器。如果需要清楚表达具体含义,请使用全称以避免歧义。

generator iterator--生成器迭代器

generator 函数所创建的对象。

每个 yield 会临时暂停处理,记住当前位置执行状态(包括局部变量和挂起的 try 语句)。

当该生成器迭代器恢复时,它会从离开位置继续执行(这与每次调用都从新开始的普通函数差别很大)。

generator expression--成器表达式

返回一个迭代器的表达式。

它看起来很像普通表达式后面带有定义了一个循环变量、范围的 for 子句,以及一个可选的 if 子句。

以下复合表达式会为外层函数生成一系列值:

>>> sum(i*i for i in range(10))         # sum of squares 0, 1, 4, ... 81
285

2.3、生成器-迭代器的方法

被用于控制生成器函数的执行。

请注意:生成器已经在执行时,调用以下任何方法都会引发 ValueError 异常。

  • generator.next()

    开始一个生成器函数的执行,或从上次执行的 yield 表达式位置恢复执行

    当一个生成器函数通过 __next__() 方法恢复执行时,当前的 yield 表达式总是取值为 None。【注:注意区分 yield 表达式的值和返回给调用者的值】

    随后会继续执行到下一个 yield 表达式,其 expression_list 的值会返回给 __next__() 的调用者。

    如果生成器没有产生下一个值就退出,则将引发 StopIteration 异常。

    此方法通常是隐式地调用,例如通过 for 循环或是内置的 next() 函数

  • generator.send(value)

    恢复执行,并向生成器函数“发送”一个值。 value 参数将成为当前 yield 表达式的结果

    send() 方法会返回生成器所产生的下一个值,或者如果生成器没有产生下一个值就退出则会引发 StopIteration。

    当调用 send() 来启动生成器时,它必须以 None 作为调用参数,因为这时没有可以接收值的 yield 表达式

  • generator.throw(type[, value[, traceback]])

    在生成器暂停的位置引发 type 类型的异常,并返回该生成器函数所产生的下一个值。

    如果生成器没有产生下一个值就退出,则将引发 StopIteration 异常。

    如果生成器函数没有捕获传入的异常,或引发了另一个异常,则该异常会被传播给调用者。

  • generator.close()

    在生成器函数暂停的位置引发 GeneratorExit。

    如果之后生成器函数正常退出、关闭或引发 GeneratorExit (由于未捕获该异常)则关闭并返回其调用者。 如果生成器产生了一个值,关闭会引发 RuntimeError。

    如果生成器引发任何其他异常,它会被传播给调用者。 如果生成器已经由于异常或正常退出则 close() 不会做任何事。

2.4、生成器理解

# 理解生成器的工作过程
>>> def reverse(data):
... for index in range(len(data)-1, -1, -1):
... yield data[index]
... >>> for char in reverse('golf'):
... print(char)
...
f
l
o
g # next(iterator[, default]) : Return the next item from the iterator.
# 上面的for循环相当于:
>>> g = reverse('golf')
>>> next(g)
'f'
>>> next(g)
'l'
>>> next(g)
'o'
>>> next(g)
'g' # 或相当于:
>>> g.__next__()
'f'
>>> g.__next__()
'l'
>>> g.__next__()
'o'
>>> g.__next__()
'g'
>>> g.__next__() # 迭代完了
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration

当一个生成器函数被调用的时候,它返回一个迭代器,称为生成器迭代器。

然后这个生成器迭代器来控制生成器函数的执行。当这个生成器迭代器的某一个方法被调用的时候【注:如__next__()】,生成器函数开始执行。

这时会一直执行到第一个 yield 表达式,在此执行再次被挂起,给生成器迭代器的调用者返回 expression_list 的值。【注:也就是返回'f''i'等值。参考 yield 表达式的语法格式部分】

挂起后,所有局部状态都被保留下来,包括局部变量的当前绑定,指令指针,内部求值栈和任何异常处理的状态。

通过调用生成器迭代器的某一个方法,生成器函数继续执行,此时函数的运行就和 yield 表达式只是一个外部函数调用的情况 完全一致。【注:继续执行时直接调用 yield 表达式】

重新开始后,yield 表达式的值取决于调用的哪个方法来恢复执行。 如果用的是 __next__() (通常通过语言内置的 for 或是 next() 来调用) 那么结果就是 None。否则,如果用 send(), 那么结果就是传递给 send 方法的值。

【注:是“yield 表达式的值”;参考下一节的generator.__next__()方法理解】

# 理解:重新开始后,yield 表达式的值取决于调用的哪个方法来恢复执行。
>>> def reverse(data):
... for index in range(len(data)-1, -1, -1):
... y = yield data[index]
... print(y)
...
>>> g = reverse('golf')
>>> g
<generator object reverse at 0x000001EE2B4875E8>
>>> g.__next__()
'f'
>>> g.__next__()
None
'l'
... >>> g = reverse('golf')
>>> g.send(None)
'f'
>>> g.send('aa')
aa
'l'
...

2.5、例子

# 整体理解生成器
>>> def echo(value=None):
... print("Execution starts when 'next()' is called for the first time.")
... try:
... while True:
... try:
... value = (yield value)
... except Exception as e:
... value = e
... finally:
... print("Don't forget to clean up when 'close()' is called.")
...
>>> generator = echo(1)
>>> print(next(generator))
Execution starts when 'next()' is called for the first time.
1
>>> print(next(generator)) # 迭代器里没有值了
None # 恢复执行,并向生成器函数“发送”一个值。 value 参数将成为当前 yield 表达式的结果
>>> print(generator.send(2)) # 这里的2发送给了`value = (yield value)`里的左边的value
2
>>> generator.throw(TypeError, "spam")
TypeError('spam',)
>>> generator.close()
Don't forget to clean up when 'close()' is called.

3、生成器表达式

生成器表达式是用圆括号括起来的紧凑形式生成器标注。

generator_expression ::=  "(" expression comp_for ")"

生成器表达式会产生一个新的生成器对象。其句法与推导式相同,区别在于它是用圆括号而不是用方括号或花括号括起来的

在生成器表达式中使用的变量会在为生成器对象调用 __next__() 方法的时候以惰性方式被求值(即与普通生成器相同的方式)。

但是,最左侧 for 子句内的可迭代对象是会被立即求值的,因此它所造成的错误会在生成器表达式被定义时被检测到,而不是在获取第一个值时才出错。

后续的 for 子句以及最左侧 for 子句内的任何筛选条件无法在外层作用域内被求值,因为它们可能会依赖于从最左侧可迭代对象获取的值。

例如:

(x*y for x in range(10) for y in range(x, x+10)).

圆括号在只附带一个参数的调用中可以被省略。 详情参见 调用 一节。

为了避免干扰到生成器表达式本身的预期操作,禁止在隐式定义的生成器中使用 yield 和 yield from 表达式


英文官方文档

中文官方文档

帮助理解

迭代器生成器阅读【Python3.8官网文档】的更多相关文章

  1. 类的基础语法阅读【Python3.8官网文档】

    英文官方文档: https://docs.python.org/3.8/tutorial/classes.html 中文官方文档: https://docs.python.org/zh-cn/3.8/ ...

  2. 你会阅读appium官网文档吗

    高效学习appium第一步,学会查看appium官方文档.如果能把appium文档都通读一遍,对学习appium大有益处. 而能做到通读appium官方文档的人,想必不是很多,刚开始学习appium的 ...

  3. mybatis官网文档mybatis_doc

    在平时的学习中,我们可以去参考官网的文档来学习,这个文档有中文的,方便我们去阅读,而且这里的分类很详细. 官网文档链接:http://www.mybatis.org/mybatis-3/zh/inde ...

  4. 部署openstack的官网文档解读mysql的配置文件

    部署openstack的官网文档解读mysql的配置文件(使用与ubutu和centos7等系统) author:headsen chen  2017-10-12 16:57:11 个人原创,严禁转载 ...

  5. redis过期机制(官网文档总结)

    官网地址:https://redis.io/commands/expire redis过期定义如下: Set a timeout on key. After the timeout has expir ...

  6. Hortonworks官网文档怎么找?

    Hortonworks官网文档怎么找? 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 俗话说,授人予鱼不如授人予渔,网上部署HDP的部署方式的博客有很多,看得你是眼花缭乱的.其实万 ...

  7. Unity shader 官网文档全方位学习(一)

    转载:https://my.oschina.net/u/138823/blog/181131 摘要: 这篇文章主要介绍Surface Shaders基础及Examples详尽解析 What?? Sha ...

  8. 【VR】Leap Motion 官网文档 FingerModel (手指模型)

    前言: 感谢关注和支持这个Leap Motion系列翻译的朋友们,非常抱歉因为工作原因非常久没有更新,今后这个翻译还会继续(除非官方直接给出中文文档).本篇献给大家的是 <FingerModel ...

  9. Spring Security 官网文档学习

    文章目录 通过`maven`向普通的`WEB`项目中引入`spring security` 配置 `spring security` `configure(HttpSecurity)` 方法 自定义U ...

随机推荐

  1. 字符串匹配算法(三)-KMP算法

    今天我们来聊一下字符串匹配算法里最著名的算法-KMP算法,KMP算法的全称是 Knuth Morris Pratt 算法,是根据三位作者(D.E.Knuth,J.H.Morris 和 V.R.Prat ...

  2. Hadoop (8088)未授权访问

    cd /vulhub/hadoop/unauthorized-yarn 加速下载环境 sudo vim /etc/docker/daemon.json 添加 {"registry-mirro ...

  3. Typora PicGo Gitee博客写作好搭档

    利用Gitee仓库存放图片 1.首先在Gitee上创建一个公开的仓库,我这里创建了一个名叫resources的仓库: 2.在Gitee中获取私人令牌(个人设置界面中): 安装配置PicGo 1.下载自 ...

  4. Sqlserver 关于varchar(max) 笔记

    看SQL server的版本,SQLserver2005以上 的nvarchar(max) 可以存放2G的内容,所以要是 SQL2005以上的nvarchar(max)足够你用的了.用nvarchar ...

  5. 学习Android Jetpack? 入门教程和进阶实战这里全都有!

    前言 2018年谷歌I/O,Jetpack横空出世,官方介绍如下: Jetpack 是一套库.工具和指南,可帮助开发者更轻松地编写优质应用.这些组件可帮助您遵循最佳做法.让您摆脱编写样板代码的工作并简 ...

  6. 以TiDB热点问题来谈Region的调度流程

    什么是热点问题 说这个话题之前我们先回顾一下TiDB的主要结构和概念. TiDB的核心架构分为TiDB.TiKV.PD三个部分,其中TiKV是一个分布式数据存储引擎用来存储真实的数据,在TiKV中又对 ...

  7. Android WorkManager使用入门

    WorkManager使用入门 WorkManager提供了任务调度功能,我们可以对工作进行标记或命名. 我们用一个示例来演示如何使用WorkManager.本文使用Kotlin. 入门示例 grad ...

  8. Asp.Net Core 导入Excel数据到Sqlite数据库并重新导出到Excel

    Asp.Net Core 导入Excel数据到Sqlite数据库并重新导出到Excel 在博文"在Asp.Net Core 使用 Sqlite 数据库"中创建了ASP.NET Co ...

  9. 线程 Thread类 GIL锁 信号量 Event事件

    线程的开启方法 进程是操作系统调度的最小单位,一个进程最少有一个主线程,而一个进程中可以开启多个线程 from threading import Thread def task(): print('A ...

  10. noip8

    T1 星际旅行 考试时觉得是道数学题,但没想到忘了欧拉路. 首先将每条边都拆成两条边,那么题目就变成了任意删掉两条边,使得新的图中存在欧拉路.设 \(sum\) 表示自环的数量, \(du_{i}\) ...