Python Iterable Iterator Yield
可以直接作用于for循环的数据类型有以下几种:
一类是集合数据类型,如list / tuple / dict / set / str /等(对于这类iterable的对象,因为你可以按照你的意愿进行重复的读取。但是你不得不预先存储所有的元素在内存中,那些对象里有很多元素时,并不是每一项都对你有用)
一类是generator,包括生成器和带yield的generator function。(生成器同样是可迭代对象,但是你只能读取一次,因为它并没有把所有值存放内存中,它动态的生成值)
这些可以直接作用于for循环的对象统称为可迭代对象:Iterable。
可以使用isinstance()判断一个对象是否是Iterable对象:
- >>> from collections import Iterable
- >>> isinstance('abc', Iterable)
- True
- >>> isinstance([1,2,3], Iterable)
- True
- >>> isinstance(100, Iterable)
- False
- >>> isinstance((x for x in range(10)), Iterable)
- True
- >>> isinstance((x for x in xrange(10)), Iterable)
- True
- >>> isinstance(set(),Iterable)
- True
而生成器不但可以作用于for循环,还可以被next()函数不断调用并返回下一个值,直到最后抛出StopIteration错误表示无法继续返回下一个值了。
可以被next()函数调用并不断返回下一个值的对象称为迭代器:Iterator。
可以使用isinstance()判断一个对象是否是Iterator对象:
- >>> from collections import Iterator
- >>> isinstance((x for x in range(20)),Iterator)
- True
- >>> isinstance([1,2,3],Iterator)
- False
- >>> isinstance(set(),Iterator)
- False
生成器都是Iterator对象,但 list / dict / str虽然是Iterable,却不是Iterator
为什么list / dict / str 等数据类型不是Iterator ?
这是因为Python的Iterator对象表示的是一个数据流,Iterator对象可以被next()函数调用并不断返回下一个数据,直到没有数据时抛出StopIteration错误。可以把这个数据流看作是一个有序序列,但我们却不能提前知道序列的长度,只能不断通过next()函数实现按需计算下一个数据,所以Iterator的计算是惰性的,只有在需要返回下一个数据时它才会计算。
Iterator甚至可以表示一个无限大的数据流,例如全体自然数。而使用list是永远不可能存储全体自然数的。
小结
凡是可作用于for循环的对象都是Iterable(可迭代对象)类型;
凡是可以作用于next()函数的对象都是Iterator类型,它们表示一个惰性计算的序列;
集合数据类型如 list / dict / str / 等是Iterable可迭代对象但不是Iterator迭代器,不过可以通过iter()函数可以获得一个Iterator对象。
Python的for循环本质上就是通过不断调用next()函数实现的,例如:
- for x in [1,2,3,4,5]:
- print x
- ix=iter([1,2,3,4,5])
- while True:
- try:
- print ix.next()
- except StopIteration:
- print "Bottom of Iterator"
- break
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!
- print getsizeof(mygenerator)
- <generator object createGenerator at 0x0000000009626D38>
- 72
一个计算斐波那契(Fibonacci)的例子
a)
- def fab(max):
- n, a, b =0, 0, 1
- while n < max:
- print b
- a, b =b, a +b
- n =n +1
- fab(5)
b)a的写法会直接在 fab 函数中用 print 打印数字会导致该函数可复用性较差,因为 fab 函数返回 None,其他函数无法获得该函数生成的数列。要提高 fab 函数的可复用性,最好不要直接打印出数列,而是返回一个 List.
- def fab(max):
- n, a, b =0, 0, 1
- L =[]
- while n < max:
- L.append(b)
- a, b =b, a +b
- n =n +1
- return L
- for n in fab(5):
- print n
c) b在运行中占用的内存会随着参数 max 的增大而增大,如果要控制内存占用,最好不要用 List来保存中间结果,而是通过 iterable 对象来迭代
- def fab(max):
- n, a, b =0, 0, 1
- L =[]
- for i in xrange(max):
- L.append(b)
- a, b =b, a +b
- return L
- for n in fab(5):
- print n
d)
- class Fab(object):
- def __init__(self, max):
- self.max=max
- self.n, self.a, self.b =0, 0, 1
- def __iter__(self):
- returnself
- def next(self):
- if self.n < self.max:
- r =self.b
- self.a, self.b =self.b, self.a +self.b
- self.n =self.n +1
- return r
- raise StopIteration()
- f=fab(5)
- f.next()
- f.next()
- f.next()
- f.next()
- f.next()
e)d的代码远远没有a的fab 函数来得简洁。如果我们想要保持第一版 fab 函数的简洁性,同时又要获得 iterable 的效果,yield 就派上用场了
- def fab(max):
- n, a, b =0, 0, 1
- while n < max:
- yield b
- # print b
- a, b =b, a +b
- n =n +1
- for n in fab(5):
- print n
- type(fab(5))
- 1
- 1
- 2
- 3
- 5
- generator
f)最后优化的版本在for循环的时候选择xrange并且结果保存在iterator里
- def fab(max):
- n,a,b=0,0,1
- for i in xrange(max):
- yield b
- a,b,=b,a+b
- for n in fab(5):
- print n
一个带有 yield 的函数就是一个 generator,它和普通函数不同,生成一个 generator 看起来像函数调用,但不会执行任何函数代码,直到对其调用 next()(在 for 循环中会自动调用 next())才开始执行。虽然执行流程仍按函数的流程执行,但每执行到一个 yield 语句就会中断,并返回一个迭代值,下次执行时从 yield 的下一个语句继续执行。看起来就好像一个函数在正常执行的过程中被 yield 中断了数次,每次中断都会通过 yield 返回当前的迭代值。
yield 的好处是显而易见的,把一个函数改写为一个 generator 就获得了迭代能力,比起用类的实例保存状态来计算下一个 next() 的值,不仅代码简洁,而且执行流程异常清晰
- from inspect import isgeneratorfunction
- isgeneratorfunction(fab)
- True
要注意区分 fab 和 fab(5),fab 是一个 generator function,而 fab(5) 是调用 fab 返回的一个 generator,好比类的定义和类的实例的区别
在一个 generator function 中,如果没有 return,则默认执行至函数完毕,如果在执行过程中 return,则直接抛出 StopIteration 终止迭代
- import types
- isinstance(fab,types.GeneratorType)
- False
- isinstance(fab(5),types.GeneratorType)
- True
- from collections import Iterable
- isinstance(fab,Iterable)
- False
- isinstance(fab(5),Iterable)
- True
另一个例子
另一个 yield 的例子来源于文件读取。如果直接对文件对象调用 read() 方法,会导致不可预测的内存占用。好的方法是利用固定长度的缓冲区来不断读取文件内容。通过 yield,我们不再需要编写读文件的迭代类,就可以轻松实现文件读取
- def read_file(fpath):
- block_size=1024
- with open(fpath,'rb') as f:
- while True:
- block=f.read(block_size)
- if block:
- yield block
- else:
- return
- rf=read_file("C:/****/cookies.txt")
- print rf.next()
- print rf.next()
- print rf.next()
Python Iterable Iterator Yield的更多相关文章
- python中的Iterable, Iterator,生成器概念
https://nychent.github.io/articles/2016-05/about-generator.cn 这个深刻 谈起Generator, 与之相关的的概念有 - {list, s ...
- Python(五) 迭代器(Iterable/Iterator/iter())
原文的链接:http://www.liaoxuefeng.com/wiki/0014316089557264a6b348958f449949df42a6d3a2e542c000/00143178254 ...
- 生成器(generator)和迭代(iterable , iterator, iteration)
在搞清楚Generator之前,我们先讨论一下 iterable , iterator, iteration 1.Iterable 我们知道,在Python中所有东西都是object, 比如说变量,容 ...
- python 迭代器 Iterator
一.可迭代对象定义 可以直接作用于for循环的数据类型有以下几种: 一类是集合数据类型,如list.tuple.dict.set.str.bytes.bytearray等: 一类是generator, ...
- 关于Python中的yield
关于Python中的yield 在介绍yield前有必要先说明下Python中的迭代器(iterator)和生成器(constructor). 一.迭代器(iterator) 在Python中,f ...
- (转) Python Generators(生成器)——yield关键字
http://blog.csdn.net/scelong/article/details/6969276 生成器是这样一个函数,它记住上一次返回时在函数体中的位置.对生成器函数的第二次(或第 n 次) ...
- [Python学习]Iterator 和 Generator的学习心得
[Python学习]Iterator 和 Generator的学习心得 Iterator是迭代器的意思,它的作用是一次产生一个数据项,直到没有为止.这样在 for 循环中就可以对它进行循环处理了.那么 ...
- python协程--yield和yield from
字典为动词“to yield”给出了两个释义:产出和让步.对于 Python 生成器中的 yield 来说,这两个含义都成立.yield item 这行代码会产出一个值,提供给 next(...) 的 ...
- 深入理解Python中的yield和send
send方法和next方法唯一的区别是在执行send方法会首先把上一次挂起的yield语句的返回值通过参数设定,从而实现与生成器方法的交互. 但是需要注意,在一个生成器对象没有执行next方法之前,由 ...
随机推荐
- 发布mvc遇到的HTTP错误 403.14-Forbidden解决办法
发布mvc遇到的HTTP错误 403.14-Forbidden解决办法 <system.webServer> <validationvalidateIntegratedMod ...
- android.app.Activity阅读摘要,有时候会不会需要保持一些现场数据呢? 想让系统帮你退出到后台或者挂掉前做些前置保持工作吗,重点参考吧:
* * @param savedInstanceState If the activity is being re-initialized after * previously being shut ...
- 关于selenium2(webdriver)自动化测试过程中标签页面或者窗口切换的处理解决方案
1. 通过页面或者window 的name切换: switch_to_frame(name) switch_to_window(name) 那么问题来了,出现2个或者以上窗口时候,新打开的windo ...
- varnish 内置函数详细说明
Subroutine列表 •vcl_recv 在请求开始时候被调用,在请求已经被接收到并且解析后调用.目的就是决定是否处理这个请求,怎么处理,使用哪个后端.vcl_recv以return结束,参数可以 ...
- jquery+php+mysql实现Ajax省市县三级联动
1.第一步建立一个html页面的,放置省.市.县三个select选择框,代码如下: <!DOCTYPE html> <html> <head> <title& ...
- Memcache所有方法及参数详解
memcache函数所有的方法列表如下: 参考http://www.php.net/manual/zh/function.Memcache-add.php Memcache::add - 添加一个值, ...
- 【.net部署】Server Error in '/' Application.错误解决方案
报错: Server Error in '/' Application.---------------------------------------------------------------- ...
- EasyUI 开发笔记(一)
由于某些原因,在公司做的后台需要改成类似于Ext.js 形式的后台,主要看好其中的 框架布局,以及tab开页面和弹出式内部窗体. 后来看看,改成EasyUI,较Ext.js 库小很多,也便于公司的初级 ...
- MVC 从后台页面 取前台页面传递过来的值的几种取法
MVC 从后台页面 取前台页面传递过来的值的几种取法 <1>前台页面 Index视图 注意:用户名表单的name值为txtName 密码表单的name值为txtPassword & ...
- SDK截图(四):压缩位图实例
这个问题研究了两天.<windows程序设计>中没有给出实例,MSDN也没有给出具体的例子.在知道,CSDN提问后,也没有得到答案.所以决定重新对DIB做一次彻底的研究,这大概会花去我一个 ...