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. 电脑软件安装过程文档.BA

    MD 01-打印并阅读-电脑软件安装过程文档.BAT-即此批处理脚本文档MD 02-阅读-电脑软件安装经验教训文档.DOCX-MD 03-制作-杏雨梨云USB维护系统2019中秋版之国庆更新-可启动U ...

  2. SQL语句(六)分页查询和联合查询

    目录 一.分页查询 语法格式 应用 二.联合查询 语法和作用 特点 应用 UNION和UNION ALL的区别 一.分页查询 语法格式 SELECT 查询列表 FROM 表 WHERE ... GRO ...

  3. javascript 特殊字符 注意转义

  4. Java数组01——声明创建、赋值及特点

    数组声明创建 数组的四个基本特点 例子  package array; ​ public class ArrayDemon01 {     //变量的类型   变量的名字   = 变量的值     / ...

  5. RHCSA_DAY05

    计算机硬件组成部分 输入设备:键盘.鼠标.触控屏等 主机设备:主板.中央处理器(CPU).主存储器(内存).网卡.声卡.显示卡等 输出设备:屏幕.耳机.打印机.投影仪等 外部存储设备:硬盘.软盘.光盘 ...

  6. [C++]-map和unordered_map

    转自:https://blog.csdn.net/BillCYJ/article/details/78985895 头文件不同 map: #include < map > unordere ...

  7. FreeRTOS-05-队列

    说明 本文仅作为学习FreeRTOS的记录文档,作为初学者肯定很多理解不对甚至错误的地方,望网友指正. FreeRTOS是一个RTOS(实时操作系统)系统,支持抢占式.合作式和时间片调度.适用于微处理 ...

  8. PrismWPF网盘

    技术点 文件分片上传与下载 Vue 正在努力中.... 客户端 采用 WPF:Net5+Prism8+RestSharp 客户端基本结构如下 模块说明 Model: 主要放置Prism模块 ZFile ...

  9. Apache虚拟web主机构建

    目录 一.构建虚拟web主机 1.1.虚拟web主机概述 二.搭建虚拟web主机步骤 2.1.基于域名搭建虚拟主机 ①为虚拟主机提供域名解析 ②为虚拟主机准备网页文档 ③添加虚拟主机配置 ④设置访问路 ...

  10. 用kivy学习制作简易调色画板app

    制作一款简易的调色画板,要用到的知识:页面布局.ToggleButton.ToggleButtonBehavior.get_color_from_hex(兼容十六进制编码颜色):功能上要可以选择颜色, ...