Python关键字yield详解以及Iterable 和Iterator区别
迭代器(Iterator)
为了理解yield是什么,首先要明白生成器(generator)是什么,在讲生成器之前先说说迭代器(iterator),当创建一个列表(list)时,你可以逐个的读取每一项,这就叫做迭代(iteration)。
- mylist = [1, 2, 3]
- for i in mylist :
- print(i)
- 1
- 2
- 3
Mylist就是一个迭代器,不管是使用复杂的表达式列表,还是直接创建一个列表,都是可迭代的对象。
- mylist = [x*x for x in range(3)]
- for i in mylist :
- print(i)
- 0
- 1
- 4
你可以使用“for··· in ···”来操作可迭代对象,如:list,string,files,这些迭代对象非常方便我们使用,因为你可以按照你的意愿进行重复的读取。但是你不得不预先存储所有的元素在内存中,那些对象里有很多元素时,并不是每一项都对你有用。
生成器(Generators)
生成器同样是可迭代对象,但是你只能读取一次,因为它并没有把所有值存放内存中,它动态的生成值:
- mygenerator = (x*x for x in range(3))
- for i in mygenerator :
- print(i)
- 0
- 1
- 4
使用()和[]结果是一样的,但是,第二次执行“ for in mygenerator”不会有任何结果返回,因为它只能使用一次。首先计算0,然后计算1,之后计算4,依次类推。
Yield
Yield是关键字, 用起来像return,yield在告诉程序,要求函数返回一个生成器。
- def createGenerator() :
- mylist = range(3)
- for i in mylist :
- yield i*i
- mygenerator = createGenerator() # create a generator
- print(mygenerator) # mygenerator is an object!
- <generator object createGenerator at 0xb7555c34>
- for i in mygenerator:
- print(i)
- 0
- 1
- 4
这个示例本身没什么意义,但是它很清晰地说明函数将返回一组仅能读一次的值,要想掌握yield,首先必须理解的是:当你调用生成器函数的时候,如上例中的createGenerator(),程序并不会执行函数体内的代码,它仅仅只是返回生成器对象,这种方式颇为微妙。函数体内的代码只有直到每次循环迭代(for)生成器的时候才会运行。
函数第一次运行时,它会从函数开始处直到碰到yield时,就返回循环的第一个值,然后,交互的运行、返回,直到没有值返回为止。如果函数在运行但是并没有遇到yield,就认为该生成器是空,原因可能是循环终止,或者没有满足任何”if/else”。
接下来读一小段代码来理解生成器的优点:
控制生成器穷举
- >>> class Bank(): # 创建银行,构造ATM机
- ... crisis = False
- ... def create_atm(self) :
- ... while not self.crisis :
- ... yield "$100"
- >>> hsbc = Bank() # 没有危机时,你想要多少,ATM就可以吐多少
- >>> corner_street_atm = hsbc.create_atm()
- >>> print(corner_street_atm.next())
- $100
- >>> print(corner_street_atm.next())
- $100
- >>> print([corner_street_atm.next() for cash in range(5)])
- ['$100', '$100', '$100', '$100', '$100']
- >>> hsbc.crisis = True # 危机来临,银行没钱了
- >>> print(corner_street_atm.next())
- <type 'exceptions.StopIteration'>
- >>> wall_street_atm = hsbc.ceate_atm() # 新建ATM,银行仍然没钱
- >>> print(wall_street_atm.next())
- <type 'exceptions.StopIteration'>
- >>> hsbc.crisis = False # 麻烦就是,即使危机过后银行还是空的
- >>> print(corner_street_atm.next())
- <type 'exceptions.StopIteration'>
- >>> brand_new_atm = hsbc.create_atm() # 构造新的ATM,恢复业务
- >>> for cash in brand_new_atm :
- ... print cash
- $100
- $100
- $100
- $100
- $100
- $100
- $100
- $100
- $100
对于访问控制资源,生成器显得非常有用。
迭代工具,你最好的朋友
迭代工具模块包含了操做指定的函数用于操作迭代器。想复制一个迭代器出来?链接两个迭代器?以one liner(这里的one-liner只需一行代码能搞定的任务)用内嵌的列表组合一组值?不使用list创建Map/Zip?···,你要做的就是 import itertools,举个例子吧:
四匹马赛跑到达终点排名的所有可能性:
- >>> horses = [1, 2, 3, 4]
- >>> races = itertools.permutations(horses)
- >>> print(races)
- <itertools.permutations object at 0xb754f1dc>
- >>> print(list(itertools.permutations(horses)))
- [(1, 2, 3, 4),
- (1, 2, 4, 3),
- (1, 3, 2, 4),
- (1, 3, 4, 2),
- (1, 4, 2, 3),
- (1, 4, 3, 2),
- (2, 1, 3, 4),
- (2, 1, 4, 3),
- (2, 3, 1, 4),
- (2, 3, 4, 1),
- (2, 4, 1, 3),
- (2, 4, 3, 1),
- (3, 1, 2, 4),
- (3, 1, 4, 2),
- (3, 2, 1, 4),
- (3, 2, 4, 1),
- (3, 4, 1, 2),
- (3, 4, 2, 1),
- (4, 1, 2, 3),
- (4, 1, 3, 2),
- (4, 2, 1, 3),
- (4, 2, 3, 1),
- (4, 3, 1, 2),
- (4, 3, 2, 1)]
理解迭代的内部机制:
迭代(iteration)就是对可迭代对象(iterables,实现了__iter__()方法)和迭代器(iterators,实现了__next__()方法)的一个操作过程。可迭代对象是任何可返回一个迭代器的对象,迭代器是应用在迭代对象中迭代的对象,换一种方式说的话就是:iterable对象的__iter__()方法可以返回iterator对象,iterator通过调用next()方法获取其中的每一个值(译者注),读者可以结合Java API中的 Iterable接口和Iterator接口进行类比。
(
java Iterable接口:
public interface Iterable<T>
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<E>
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则不然,每次调用都会返回一个从头开始计数的迭代器。
多个迭代器是互不干扰的
英文原文:The Python yield keyword explained
原文链接:http://blog.jobbole.com/32748/
Python关键字yield详解以及Iterable 和Iterator区别的更多相关文章
- (转)python collections模块详解
python collections模块详解 原文:http://www.cnblogs.com/dahu-daqing/p/7040490.html 1.模块简介 collections包含了一些特 ...
- python协程详解
目录 python协程详解 一.什么是协程 二.了解协程的过程 1.yield工作原理 2.预激协程的装饰器 3.终止协程和异常处理 4.让协程返回值 5.yield from的使用 6.yield ...
- python协程详解,gevent asyncio
python协程详解,gevent asyncio 新建模板小书匠 #协程的概念 #模块操作协程 # gevent 扩展模块 # asyncio 内置模块 # 基础的语法 1.生成器实现切换 [1] ...
- Python中dict详解
from:http://www.cnblogs.com/yangyongzhi/archive/2012/09/17/2688326.html Python中dict详解 python3.0以上,pr ...
- 【python进阶】详解元类及其应用2
前言 在上一篇文章[python进阶]详解元类及其应用1中,我们提到了关于元类的一些前置知识,介绍了类对象,动态创建类,使用type创建类,这一节我们将继续接着上文来讲~~~ 5.使⽤type创建带有 ...
- python第七篇:Python 列表操作详解
Python列表操作详解 list函数 list() #生成一个空的列表 list(iterable) #用可迭代对象初始化一个列表 列表的 and 运算和 or 运算 列表and运算 > ...
- Python函数参数详解
Python函数参数详解 形参与实参 什么是形参 在定义函数阶段定义的参数称之为形式参数,简称形参,相当于变量名. 什么是实参 在调用函数阶段传入的值称为实际参数,简称实参.相当于"变量值& ...
- Python 字符串方法详解
Python 字符串方法详解 本文最初发表于赖勇浩(恋花蝶)的博客(http://blog.csdn.net/lanphaday),如蒙转载,敬请保留全文完整,切勿去除本声明和作者信息. ...
- Python关键字yield的解释(stackoverflow)
3.1. 提问者的问题 Python关键字yield的作用是什么?用来干什么的? 比如,我正在试图理解下面的代码: def node._get_child_candidates(self, dista ...
随机推荐
- MFC模式对话框与非模式对话框 消息处理顺序
对话框有两种创建方式:DoModal和Creat. 其中DoModal创建的是模态的对话框,而Creat创建的是非模态的对话框下面总结下他们的不同. 对于模态的对话框,在该对话框被关闭前,用户将不能在 ...
- HDU 4727 The Number Off of FFF
The Number Off of FFF Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Other ...
- Git基础 1 ---- 版本控制系统的介绍
1 Git 1 版本控制系统 vcs - version control system 2 版本控制是一种记录一个或若干文件内容变化,以便将来查阅特定版本修订情况的系统 3 版本控制系统的主要功能 1 ...
- js设置奇偶行数样式
$(document).ready(function () { odd = { "background": "none" }; //奇数样式 even = { ...
- CSS3属性值之box-shadow
语法: box-shadow:inset x-offset y-offset blur-radius spread-radius color 也就是: 对象选择器 {box-shadow:投影 ...
- ajax 简单操作
<script> $(function () { //$("#send").click(function () { // $.get("JQuery.as ...
- 鼠标放上去图片慢慢变大js 或 变大
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...
- BZOJ 3675: [Apio2014]序列分割( dp + 斜率优化 )
WA了一版... 切点确定的话, 顺序是不会影响结果的..所以可以dp dp(i, k) = max(dp(j, k-1) + (sumn - sumi) * (sumi - sumj)) 然后斜率优 ...
- Python之美[从菜鸟到高手]--urlparse源码分析
urlparse是用来解析url格式的,url格式如下:protocol :// hostname[:port] / path / [;parameters][?query]#fragment,其中; ...
- Node.js学习笔记3(快速入门)
一.开始使用Node.js编程 1.hello world 好了,让我们开始实现第一个 Node.js 程序吧.打开你常用的文本编辑器,在其中输入 ...