迭代

维基百科对迭代的定义如下

迭代是重复反馈过程的活动,其目的通常是为了接近并到达所需的目标或结果。每一次对过程的重复被称为一次“迭代”,而每一次迭代得到的结果会被用来作为下一次迭代的初始值。


可迭代对象(iterable) 与 迭代器(iterator)

关系如下图:

可迭代对象( iterable ) 是实现了__iter__()方法的对象
迭代器( iterator)是实现了__iter__()__next__()方法的对象
可迭代对象( iterable )通过调用 iter() 方法得到一个 迭代器( iterator)

可迭代对象的特点:能够使⽤for…in…的循环语法的对象,即 list、tuple、str 等类型的对象
迭代器对象的特点:该对象是消耗型的,即对该对象每遍历一次,就消失一个值,遍历完后,就变成了一个空的容器,但不等于 None。

通过如下代码,可以很清楚的认识可迭代对象迭代器的特点与联系

>>> from collections import Iterable, Iterator
>>> a = [1,2,3]   # 众所周知,list是一个iterable
>>> b = iter(a)   # 通过iter()方法,得到iterator,iter()实际上调用了__iter__(),此后不再多说
>>> isinstance(a, Iterable)
True
>>> isinstance(a, Iterator)
False
>>> isinstance(b, Iterable)
True
>>> isinstance(b, Iterator)
True
# 可见,itertor一定是iterable,但iterable不一定是itertor# iterator是消耗型的,用一次少一次.对iterator进行变量,iterator就空了!
>>> c = list(b)
>>> c
[1, 2, 3]
>>> d = list(b)
>>> d
[]# 空的iterator并不等于None.
>>> if b:
...   print(1)
...
1
>>> if b == None:
...   print(1)
...# 再来感受一下next()
>>> e = iter(a)
>>> next(e)     #next()实际调用了__next__()方法,此后不再多说
1
>>> next(e)
2

然提到了for … in …语句,我们再来简单讲下其工作原理吧,或许能帮助理解以上所讲的内容

>>> x = [1, 2, 3]
>>> for i in x:
...     ...

我们对一个iterable用for … in …进行迭代时,实际是先通过调用iter()方法得到一个iterator,假设叫做X.然后循环地调用X的next()方法取得每一次的值,直到iterator为空,返回的StopIteration作为循环结束的标志 for … in … 会自动处理StopIteration异常,从而避免了抛出异常而使程序中断。如图所示


生成器

迭代器与生成器的区别:
1、生成器是一种特殊的迭代器,所以迭代器的用法可以用于生成器
2、要定义一个迭代器,需要分别实现__iter__()方法和__next__()方法
3、要定义生成器,只需要一个 yield

生成器,即带有yield的函数,是一种特殊的迭代器,包含生成器函数和生成器表达式(形如(elem for elem in [1, 2, 3])的表达式)

示例代码如下:

>>> a = (elem for elem in [1, 2, 3])
>>> a
<generator object <genexpr> at 0x7f0d23888048>
>>> def fib():
...     a, b = 0, 1
...     while True:
...         yield b
...         a, b = b, a + b
...
>>> b = fib()
<generator object fib at 0x7f0d20bbfea0>

生成器的调用方法:
示例代码:

>>> def gen():
...     while True:
...         s = yield
...         print(s)
...
>>> g = gen()
>>> g.send("kissg")
Traceback (most recent call last):File "<stdin>", line 1, in <module>
TypeError: can't send non-None value to a just-started generator
>>> next(g)
>>> g.send("kissg")
kissg

问题所在:调用 send(value) 时要注意,要确保 generator 是在yield 处被暂停了,如此才能向 yield 表达式传值,否则将会报错(如上所示),可通过 next() 方法或send(None) 使generator执行到yield。

再来看一段yield更复杂的用法,或许能加深你对generator的next()与send(value)的理解。

>>> def echo():
...     for row in range(5):
...         s = yield row   #若此处 yield 后面无参数,则默认值为 None。通过send(value)方法将value作为yield表达式的当前值
...         print("This value is: ", value)
...
>>> g = echo()
>>> g.send(None)  # 或者换成 next(g)
0
>>> g.send("hello")
This value is: hello
1
>>>
>>> g.send("world")    # 获取 s = yield row 中的 s 值
This value is: world
2
>>>
>>> next(g)            # 获取 echo() 对象的值
This value is: None
3
>>>
>>> next(g)
This value is: None
4

使用生成器实现生产者消费者模式,代码如下:

import threading
import time# 消费者
def consumer():data = ''while True:r = yield datadata = '生产的'+r+'还不错'time.sleep(1)# 生产者
def produce(con):con.send(None)   #可通过 next() 方法或send(None) 使生成器执行到yield,才能进行下一步生产消费操作for i in range(5):print('生产者生产了%d' % i)r = con.send(str(i))print(r)
if __name__ == '__main__':m = consumer()produce(m)

综上,yield 作为一个暂停恢复的点,代码从yield处恢复,又在下一个yield处暂停。可见,在一次 next() (非首次)或 send(value) 调用过程中,实际上存在2个 yield,一个作为恢复点的 yield 与一个作为暂停点的 yield。因此,也就有2个yield表达式。send(value) 方法是将值传给恢复点yield,调用next()表达式的值时,其恢复点yield的值总是为None,而将暂停点的yield表达式的值返回。

使用yield实现协程

#!/usr/bin/pythondef consumer():r = ''while True:n = yield rif not n:print("not n...")returnprint('[CONSUMER] Consuming %s...' % n)r = '200 OK'def produce(c):f = c.send(None)print('[PRODUCER] Consumer first return: %s' % f)n = 0while n < 2:n = n + 1print('[PRODUCER] Producing %s...' % n)r = c.send(n)print('[PRODUCER] Consumer return: %s' % r)c.close()c = consumer()
produce(c)

运行结果:

[PRODUCER] Consumer first return:
[PRODUCER] Producing 1...
[CONSUMER] Consuming 1...
[PRODUCER] Consumer return: 200 OK
[PRODUCER] Producing 2...
[CONSUMER] Consuming 2...
[PRODUCER] Consumer return: 200 OK

协程的说明:

注意到consumer函数是一个generator,把一个consumer传入produce后:

  1. 首先调用c.send(None)启动生成器;
  2. 然后,一旦生产了东西,通过c.send(n)切换到consumer执行;
  3. consumer通过yield拿到消息,处理,又通过yield把结果传回;
  4. produce拿到consumer处理的结果,继续生产下一条消息;
  5. produce决定不生产了,通过c.close()关闭consumer,整个过程结束。

整个流程无锁,由一个线程执行,produce和consumer协作完成任务,所以称为“协程”,而非线程的抢占式多任务。

参考文档:
http://kissg.me/2016/04/09/python-generator-yield/
https://www.cnblogs.com/fangyuan1004/p/4571304.html

Python之生成器详解相关推荐

  1. python协程详解

    目录 python协程详解 一.什么是协程 二.了解协程的过程 1.yield工作原理 2.预激协程的装饰器 3.终止协程和异常处理 4.让协程返回值 5.yield from的使用 6.yield ...

  2. python六大数据类型详解

    python 六大数据类型详解 文章目录 python 六大数据类型详解 数据类型简介 Number(数值) String(字符串) Python字符串的45个方法详解 一.大小写转换 01.capi ...

  3. python协程详解_python协程详解

    原博文 2019-10-25 10:07 − # python协程详解 ![python协程详解](https://pic2.zhimg.com/50/v2-9f3e2152b616e89fbad86 ...

  4. python20191031_20191031:Python取反运算详解

    20191031:Python取反运算详解 取反运算:~3 == 4 1.对于数字 3 =======>转换为二进制表示为011 2.对011取反为100 3.为什么表示-4 a.计算机用补码表 ...

  5. Python字符编码详解

    Python字符编码详解 转自http://www.cnblogs.com/huxi/archive/2010/12/05/1897271.html Python字符编码详解 本文简单介绍了各种常用的 ...

  6. python的执行过程_在交互式环境中执行Python程序过程详解

    前言 相信接触过Python的伙伴们都知道运行Python脚本程序的方式有多种,目前主要的方式有:交互式环境运行.命令行窗口运行.开发工具上运行等,其中在不同的操作平台上还互不相同.今天,小编讲些Py ...

  7. windows上安装Anaconda和python的教程详解

    一提到数字图像处理编程,可能大多数人就会想到matlab,但matlab也有自身的缺点: 1.不开源,价格贵 2.软件容量大.一般3G以上,高版本甚至达5G以上. 3.只能做研究,不易转化成软件. 因 ...

  8. python变量类型-Python 变量类型详解

    变量存储在内存中的值.这就意味着在创建变量时会在内存中开辟一个空间. 基于变量的数据类型,解释器会分配指定内存,并决定什么数据可以被存储在内存中. 因此,变量可以指定不同的数据类型,这些变量可以存储整 ...

  9. python安装教程windows-windows上安装Anaconda和python的教程详解

    一提到数字图像处理编程,可能大多数人就会想到matlab,但matlab也有自身的缺点: 1.不开源,价格贵 2.软件容量大.一般3G以上,高版本甚至达5G以上. 3.只能做研究,不易转化成软件. 因 ...

最新文章

  1. 【校招面试 之 C/C++】第16题 C++ new和delete的实现原理
  2. 简单天气应用开发——基本功能完成
  3. springboot actuator_Spring Boot 服务监控,健康检查,线程信息,JVM堆信息,指标收集,运行情况监控...
  4. One order event display tool
  5. Windows CE创建桌面快捷方式
  6. 硅谷还是程序员的“圣地”吗?
  7. 每天5分钟玩转docker容器技术 pdf_stack 的优势 每天5分钟玩转 Docker 容器技术(113)...
  8. 2d头发_3D打印毛囊突破性进展!“头发工厂”将成秃顶的救星
  9. Java语言中的----条件循环
  10. SDRAM学习笔记(二)
  11. 神舟计算机主板bios,神舟笔记本BIOS设置详解
  12. edge便捷截取长图
  13. Ubiquitous Religions POJ - 2524
  14. 一句关于爱情的话...
  15. python第四次作业——陈灵院
  16. Office服务器意外响应,Office 所有使用过程中未响应,崩溃,意外关闭
  17. Mybatis错误 Result Maps collection already contains value for xxx
  18. win10远程桌面连接都有哪些工具
  19. 音频基础学习三——声音的时频谱
  20. 微信小程序富文本渲染(rich-text)换行失效

热门文章

  1. dnf剑魂buff等级上限_DNF:半年前没人看得上,如今被开发成T0,这神话终于翻身了...
  2. python画聚类图、并且把聚类图保存起来_Python利用igraph绘制复杂网络聚类(社区检测)结果图-Go语言中文社区...
  3. 使用“宝塔一键迁移”工具,将单机版typecho博客系统迁移到京东云cvm云主机
  4. matlab符号对象
  5. 解决 fatal: unable to access ‘https://github.com/qweertu/git-demo.git/‘: error setting certificate...
  6. 大学生访谈计算机教师,职业生涯人物访谈报告,教师(共10篇)
  7. docker重启后启动失败Failed to start Docker Application Container Engine.
  8. CSS3新增属性汇总
  9. 号外——安装ubantu操作系统16.04
  10. 借助github搭建自己的CDN服务