Python 关键字 yield 详解以及 Iterable 和 Iterator 区别

本贴最后更新于 2817 天前,其中的信息可能已经事过境迁

迭代器(Iterator)

为了理解 yield 是什么,首先要明白生成器(generator)是什么,在讲生成器之前先说说迭代器(iterator),当创建一个列表(list)时,你可以逐个的读取每一项,这就叫做迭代(iteration)。

  1. mylist = [ 1 , 2 , 3 ]
  2. for i in mylist :
  3. print (i)
  4. 1
  5. 2
  6. 3

Mylist 就是一个迭代器,不管是使用复杂的表达式列表,还是直接创建一个列表,都是可迭代的对象。

  1. mylist = [x*x for x in range( 3 )]
  2. for i in mylist :
  3. print (i)
  4. 0
  5. 1
  6. 4

你可以使用“for··· in ···”来操作可迭代对象,如:list,string,files,这些迭代对象非常方便我们使用,因为你可以按照你的意愿进行重复的读取。但是你不得不预先存储所有的元素在内存中,那些对象里有很多元素时,并不是每一项都对你有用。

生成器(Generators)

生成器同样是可迭代对象,但是你只能读取一次,因为它并没有把所有值存放内存中,它动态的生成值:

  1. mygenerator = (x*x for x in range( 3 ))
  2. for i in mygenerator :
  3. print (i)
  4. 0
  5. 1
  6. 4

使用()和[]结果是一样的,但是,第二次执行“ for in mygenerator”不会有任何结果返回,因为它只能使用一次。首先计算 0,然后计算 1,之后计算 4,依次类推。

Yield

**Yield 是关键字, 用起来像 return,yield 在告诉程序,要求函数返回一个生成 **器。

  1. def createGenerator() :

  2. mylist = range( 3 )

  3. for i in mylist :

  4. yield i*i

  5. mygenerator = createGenerator() # create a generator

  6. print (mygenerator) # mygenerator is an object!

  7. < **generator object **createGenerator at 0xb7555c34 >

  8. for i in mygenerator:

  9. print (i)

  10. 0

  11. 1

  12. 4

这个示例本身没什么意义,但是它很清晰地说明函数将返回一组仅能读一次的值,要想掌握 yield,首先必须理解的是:当你调用生成器函数的时候,如上例中的 createGenerator(),程序并不会执行函数体内的代码,它仅仅只是返回生成器对象,这种方式颇为微妙。函数体内的代码只有直到每次循环迭代(for)生成器的时候才会运行。

函数第一次运行时,它会从函数开始处直到碰到 yield 时,就返回循环的第一个值,然后,交互的运行、返回,直到没有值返回为止。如果函数在运行但是并没有遇到 yield,就认为该生成器是空,原因可能是循环终止,或者没有满足任何”if/else”。

接下来读一小段代码来理解生成器的优点:

控制生成器穷举

  1. class Bank(): # 创建银行,构造 ATM 机

  2. ... crisis = False
  3. ... def create_atm( self ) :
  4. ... while not self .crisis :
  5. ... yield "$100"
  6. hsbc = Bank() # 没有危机时,你想要多少,ATM 就可以吐多少

  7. corner_street_atm = hsbc.create_atm()

  8. print (corner_street_atm.next())

  9. $ 100
  10. print (corner_street_atm.next())

  11. $ 100
  12. print ([corner_street_atm.next() for cash in range( 5 )])

  13. [ '$100' , '$100' , '$100' , '$100' , '$100' ]
  14. hsbc.crisis = True # 危机来临,银行没钱了

  15. print (corner_street_atm.next())

  16. wall_street_atm = hsbc.ceate_atm() # 新建 ATM,银行仍然没钱

  17. print (wall_street_atm.next())

  18. hsbc.crisis = False # 麻烦就是,即使危机过后银行还是空的

  19. print (corner_street_atm.next())

  20. brand_new_atm = hsbc.create_atm() # 构造新的 ATM,恢复业务

  21. for cash in brand_new_atm :

  22. ... print cash
  23. $ 100
  24. $ 100
  25. $ 100
  26. $ 100
  27. $ 100
  28. $ 100
  29. $ 100
  30. $ 100
  31. $ 100

对于访问控制资源,生成器显得非常有用。

迭代工具,你最好的朋友

**迭代工具模块包含了操做指定的函数用于操作迭代器。 **想复制一个迭代器出来?链接两个迭代器?以 one liner(这里的 one-liner 只需一行代码能搞定的任务)用内嵌的列表组合一组值?不使用 list 创建 Map/Zip?···,你要做的就是 import itertools,举个例子吧:

四匹马赛跑到达终点排名的所有可能性:

  1. horses = [ 1 , 2 , 3 , 4 ]

  2. races = itertools.permutations(horses)

  3. print (races)

  4. print (list(itertools.permutations(horses)))

  5. [( 1 , 2 , 3 , 4 ),
  6. ( 1 , 2 , 4 , 3 ),
  7. ( 1 , 3 , 2 , 4 ),
  8. ( 1 , 3 , 4 , 2 ),
  9. ( 1 , 4 , 2 , 3 ),
  10. ( 1 , 4 , 3 , 2 ),
  11. ( 2 , 1 , 3 , 4 ),
  12. ( 2 , 1 , 4 , 3 ),
  13. ( 2 , 3 , 1 , 4 ),
  14. ( 2 , 3 , 4 , 1 ),
  15. ( 2 , 4 , 1 , 3 ),
  16. ( 2 , 4 , 3 , 1 ),
  17. ( 3 , 1 , 2 , 4 ),
  18. ( 3 , 1 , 4 , 2 ),
  19. ( 3 , 2 , 1 , 4 ),
  20. ( 3 , 2 , 4 , 1 ),
  21. ( 3 , 4 , 1 , 2 ),
  22. ( 3 , 4 , 2 , 1 ),
  23. ( 4 , 1 , 2 , 3 ),
  24. ( 4 , 1 , 3 , 2 ),
  25. ( 4 , 2 , 1 , 3 ),
  26. ( 4 , 2 , 3 , 1 ),
  27. ( 4 , 3 , 1 , 2 ),
  28. ( 4 , 3 , 2 , 1 )]

理解迭代的内部机制:

迭代(iteration)就是对可迭代对象(iterables,实现了__iter__()方法)和迭代器(iterators,实现了__next__()方法)的一个操作过程。可迭代对象是任何可返回一个迭代器的对象,迭代器是应用在迭代对象中迭代的对象,换一种方式说的话就是:iterable 对象的__iter__()方法可以返回 iterator 对象,iterator 通过调用 next()方法获取其中的每一个值(译者注),读者可以结合 Java API 中的 Iterable 接口和 Iterator 接口进行类比。

java Iterable 接口:

public interface Iterable

Implementing this interface allows an object to be the target of the "foreach" statement.

方法:

Iterator<T> iterator()

Returns an iterator over a set of elements of type T.

Returns:

an Iterator.

Iterator 接口:

public interface Iterator

An iterator over a collection. Iterator takes the place of Enumeration in the Java collections framework. Iterators differ from enumerations in two ways:

  • Iterators allow the caller to remove elements from the underlying collection during the iteration with well-defined semantics.
  • Method names have been improved.

This interface is a member of the Java Collections Framework .

boolean hasNext()
Returns true if the iteration has more elements.
E next()
Returns the next element in the iteration.
void remove()
Removes from the underlying collection the last element returned by the iterator (optional operation).

为什么一定要去实现 Iterable 这个接口呢? 为什么不直接实现 Iterator 接口呢?

看一下 JDK 中的集合类,比如 List 一族或者 Set 一族,
都是实现了 Iterable 接口,但并不直接实现 Iterator 接口。
仔细想一下这么做是有道理的。 **因为 Iterator 接口的核心方法 next()或者 hasNext()
是依赖于迭代器的当前迭代位置的。 **
如果 Collection 直接实现 Iterator 接口,势必导致集合对象中包含当前迭代位置的数据(指针)。
当集合在不同方法间被传递时,由于当前迭代位置不可预置,那么 next()方法的结果会变成不可预知。
除非再为 Iterator 接口添加一个 reset()方法,用来重置当前迭代位置。
但即时这样,Collection 也只能同时存在一个当前迭代位置。
而 Iterable 则不然,每次调用都会返回一个从头开始计数的迭代器。
多个迭代器是互不干扰的
来源 :http://blog.csdn.net/fish0058/article/details/23199249

  • 笔记

    好记性不如烂笔头。

    311 引用 • 794 回帖
  • Python

    Python 是一种面向对象、直译式电脑编程语言,具有近二十年的发展历史,成熟且稳定。它包含了一组完善而且容易理解的标准库,能够轻松完成很多常见的任务。它的语法简捷和清晰,尽量使用无异义的英语单词,与其它大多数程序设计语言使用大括号不一样,它使用缩进来定义语句块。

    554 引用 • 675 回帖

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...

推荐标签 标签

  • Spark

    Spark 是 UC Berkeley AMP lab 所开源的类 Hadoop MapReduce 的通用并行框架。Spark 拥有 Hadoop MapReduce 所具有的优点;但不同于 MapReduce 的是 Job 中间输出结果可以保存在内存中,从而不再需要读写 HDFS,因此 Spark 能更好地适用于数据挖掘与机器学习等需要迭代的 MapReduce 的算法。

    74 引用 • 46 回帖 • 565 关注
  • QQ

    1999 年 2 月腾讯正式推出“腾讯 QQ”,在线用户由 1999 年的 2 人(马化腾和张志东)到现在已经发展到上亿用户了,在线人数超过一亿,是目前使用最广泛的聊天软件之一。

    45 引用 • 557 回帖
  • Markdown

    Markdown 是一种轻量级标记语言,用户可使用纯文本编辑器来排版文档,最终通过 Markdown 引擎将文档转换为所需格式(比如 HTML、PDF 等)。

    172 引用 • 1539 回帖
  • iOS

    iOS 是由苹果公司开发的移动操作系统,最早于 2007 年 1 月 9 日的 Macworld 大会上公布这个系统,最初是设计给 iPhone 使用的,后来陆续套用到 iPod touch、iPad 以及 Apple TV 等产品上。iOS 与苹果的 Mac OS X 操作系统一样,属于类 Unix 的商业操作系统。

    89 引用 • 150 回帖 • 4 关注
  • Docker

    Docker 是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的容器中,然后发布到任何流行的操作系统上。容器完全使用沙箱机制,几乎没有性能开销,可以很容易地在机器和数据中心中运行。

    497 引用 • 934 回帖 • 1 关注
  • 服务

    提供一个服务绝不仅仅是简单的把硬件和软件累加在一起,它包括了服务的可靠性、服务的标准化、以及对服务的监控、维护、技术支持等。

    41 引用 • 24 回帖 • 1 关注
  • Webswing

    Webswing 是一个能将任何 Swing 应用通过纯 HTML5 运行在浏览器中的 Web 服务器,详细介绍请看 将 Java Swing 应用变成 Web 应用

    1 引用 • 15 回帖 • 642 关注
  • OneDrive
    2 引用 • 4 关注
  • JWT

    JWT(JSON Web Token)是一种用于双方之间传递信息的简洁的、安全的表述性声明规范。JWT 作为一个开放的标准(RFC 7519),定义了一种简洁的,自包含的方法用于通信双方之间以 JSON 的形式安全的传递信息。

    20 引用 • 15 回帖 • 27 关注
  • RIP

    愿逝者安息!

    8 引用 • 92 回帖 • 409 关注
  • 新人

    让我们欢迎这对新人。哦,不好意思说错了,让我们欢迎这位新人!
    新手上路,请谨慎驾驶!

    52 引用 • 228 回帖
  • 强迫症

    强迫症(OCD)属于焦虑障碍的一种类型,是一组以强迫思维和强迫行为为主要临床表现的神经精神疾病,其特点为有意识的强迫和反强迫并存,一些毫无意义、甚至违背自己意愿的想法或冲动反反复复侵入患者的日常生活。

    15 引用 • 161 回帖
  • 星云链

    星云链是一个开源公链,业内简单的将其称为区块链上的谷歌。其实它不仅仅是区块链搜索引擎,一个公链的所有功能,它基本都有,比如你可以用它来开发部署你的去中心化的 APP,你可以在上面编写智能合约,发送交易等等。3 分钟快速接入星云链 (NAS) 测试网

    3 引用 • 16 回帖 • 2 关注
  • jQuery

    jQuery 是一套跨浏览器的 JavaScript 库,强化 HTML 与 JavaScript 之间的操作。由 John Resig 在 2006 年 1 月的 BarCamp NYC 上释出第一个版本。全球约有 28% 的网站使用 jQuery,是非常受欢迎的 JavaScript 库。

    63 引用 • 134 回帖 • 734 关注
  • MongoDB

    MongoDB(来自于英文单词“Humongous”,中文含义为“庞大”)是一个基于分布式文件存储的数据库,由 C++ 语言编写。旨在为应用提供可扩展的高性能数据存储解决方案。MongoDB 是一个介于关系数据库和非关系数据库之间的产品,是非关系数据库当中功能最丰富,最像关系数据库的。它支持的数据结构非常松散,是类似 JSON 的 BSON 格式,因此可以存储比较复杂的数据类型。

    91 引用 • 59 回帖
  • Typecho

    Typecho 是一款博客程序,它在 GPLv2 许可证下发行,基于 PHP 构建,可以运行在各种平台上,支持多种数据库(MySQL、PostgreSQL、SQLite)。

    12 引用 • 67 回帖 • 445 关注
  • TensorFlow

    TensorFlow 是一个采用数据流图(data flow graphs),用于数值计算的开源软件库。节点(Nodes)在图中表示数学操作,图中的线(edges)则表示在节点间相互联系的多维数据数组,即张量(tensor)。

    20 引用 • 19 回帖 • 1 关注
  • Wide

    Wide 是一款基于 Web 的 Go 语言 IDE。通过浏览器就可以进行 Go 开发,并有代码自动完成、查看表达式、编译反馈、Lint、实时结果输出等功能。

    欢迎访问我们运维的实例: https://wide.b3log.org

    30 引用 • 218 回帖 • 643 关注
  • ngrok

    ngrok 是一个反向代理,通过在公共的端点和本地运行的 Web 服务器之间建立一个安全的通道。

    7 引用 • 63 回帖 • 657 关注
  • 博客

    记录并分享人生的经历。

    273 引用 • 2389 回帖
  • Ant-Design

    Ant Design 是服务于企业级产品的设计体系,基于确定和自然的设计价值观上的模块化解决方案,让设计者和开发者专注于更好的用户体验。

    17 引用 • 23 回帖 • 3 关注
  • Windows

    Microsoft Windows 是美国微软公司研发的一套操作系统,它问世于 1985 年,起初仅仅是 Microsoft-DOS 模拟环境,后续的系统版本由于微软不断的更新升级,不但易用,也慢慢的成为家家户户人们最喜爱的操作系统。

    229 引用 • 476 回帖
  • Python

    Python 是一种面向对象、直译式电脑编程语言,具有近二十年的发展历史,成熟且稳定。它包含了一组完善而且容易理解的标准库,能够轻松完成很多常见的任务。它的语法简捷和清晰,尽量使用无异义的英语单词,与其它大多数程序设计语言使用大括号不一样,它使用缩进来定义语句块。

    554 引用 • 675 回帖
  • PWL

    组织简介

    用爱发电 (Programming With Love) 是一个以开源精神为核心的民间开源爱好者技术组织,“用爱发电”象征开源与贡献精神,加入组织,代表你将遵守组织的“个人开源爱好者”的各项条款。申请加入:用爱发电组织邀请帖
    用爱发电组织官网:https://programmingwithlove.stackoverflow.wiki/

    用爱发电组织的核心驱动力:

    • 遵守开源守则,体现开源&贡献精神:以分享为目的,拒绝非法牟利。
    • 自我保护:使用适当的 License 保护自己的原创作品。
    • 尊重他人:不以各种理由、各种漏洞进行未经允许的抄袭、散播、洩露;以礼相待,尊重所有对社区做出贡献的开发者;通过他人的分享习得知识,要留下足迹,表示感谢。
    • 热爱编程、热爱学习:加入组织,热爱编程是首当其要的。我们欢迎热爱讨论、分享、提问的朋友,也同样欢迎默默成就的朋友。
    • 倾听:正确并恳切对待、处理问题与建议,及时修复开源项目的 Bug ,及时与反馈者沟通。不抬杠、不无视、不辱骂。
    • 平视:不诋毁、轻视、嘲讽其他开发者,主动提出建议、施以帮助,以和谐为本。只要他人肯努力,你也可能会被昔日小看的人所超越,所以请保持谦虚。
    • 乐观且活跃:你的努力决定了你的高度。不要放弃,多年后回头俯瞰,才会发现自己已经成就往日所仰望的水平。积极地将项目开源,帮助他人学习、改进,自己也会获得相应的提升、成就与成就感。
    1 引用 • 487 回帖 • 4 关注
  • 安装

    你若安好,便是晴天。

    132 引用 • 1184 回帖 • 2 关注
  • V2Ray
    1 引用 • 15 回帖 • 5 关注
  • 阿里巴巴

    阿里巴巴网络技术有限公司(简称:阿里巴巴集团)是以曾担任英语教师的马云为首的 18 人,于 1999 年在中国杭州创立,他们相信互联网能够创造公平的竞争环境,让小企业通过创新与科技扩展业务,并在参与国内或全球市场竞争时处于更有利的位置。

    43 引用 • 221 回帖 • 54 关注