可以直接作用于for循环的数据类型有以下几种:

一类是集合数据类型,如list / tuple / dict / set / str /等(对于这类iterable的对象,因为你可以按照你的意愿进行重复的读取。但是你不得不预先存储所有的元素在内存中,那些对象里有很多元素时,并不是每一项都对你有用)

一类是generator,包括生成器和带yield的generator function。(生成器同样是可迭代对象,但是你只能读取一次,因为它并没有把所有值存放内存中,它动态的生成值)

这些可以直接作用于for循环的对象统称为可迭代对象:Iterable。

可以使用isinstance()判断一个对象是否是Iterable对象:

  1. >>> from collections import Iterable
  2. >>> isinstance('abc', Iterable)
  3. True
  4. >>> isinstance([1,2,3], Iterable)
  5. True
  6. >>> isinstance(100, Iterable)
  7. False
  8. >>> isinstance((x for x in range(10)), Iterable)
  9. True
  10. >>> isinstance((x for x in xrange(10)), Iterable)
  11. True
  12. >>> isinstance(set(),Iterable)
  13. True

而生成器不但可以作用于for循环,还可以被next()函数不断调用并返回下一个值,直到最后抛出StopIteration错误表示无法继续返回下一个值了。

可以被next()函数调用并不断返回下一个值的对象称为迭代器:Iterator。

可以使用isinstance()判断一个对象是否是Iterator对象:

  1. >>> from collections import Iterator
  2. >>> isinstance((x for x in range(20)),Iterator)
  3. True
  4. >>> isinstance([1,2,3],Iterator)
  5. False
  6. >>> isinstance(set(),Iterator)
  7. 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()函数实现的,例如:

  1. for x in [1,2,3,4,5]:
  2. print x
  3.  
  4. ix=iter([1,2,3,4,5])
  5.  
  6. while True:
  7. try:
  8. print ix.next()
  9. except StopIteration:
  10. print "Bottom of Iterator"
  11. break

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. print getsizeof(mygenerator)
  8.  
  9. <generator object createGenerator at 0x0000000009626D38>
  10. 72

一个计算斐波那契(Fibonacci)的例子

a)

  1. def fab(max):
  2. n, a, b =0, 0, 1
  3. while n < max:
  4. print b
  5. a, b =b, a +b
  6. n =n +1
  7.  
  8. fab(5)

b)a的写法会直接在 fab 函数中用 print 打印数字会导致该函数可复用性较差,因为 fab 函数返回 None,其他函数无法获得该函数生成的数列。要提高 fab 函数的可复用性,最好不要直接打印出数列,而是返回一个 List.

  1. def fab(max):
  2. n, a, b =0, 0, 1
  3. L =[]
  4. while n < max:
  5. L.append(b)
  6. a, b =b, a +b
  7. n =n +1
  8. return L
  9.  
  10. for n in fab(5):
  11. print n

c) b在运行中占用的内存会随着参数 max 的增大而增大,如果要控制内存占用,最好不要用 List来保存中间结果,而是通过 iterable 对象来迭代

  1. def fab(max):
  2. n, a, b =0, 0, 1
  3. L =[]
  4. for i in xrange(max):
  5. L.append(b)
  6. a, b =b, a +b
  7. return L
  8.  
  9. for n in fab(5):
  10. print n

d)

  1. class Fab(object):
  2.  
  3. def __init__(self, max):
  4. self.max=max
  5. self.n, self.a, self.b =0, 0, 1
  6.  
  7. def __iter__(self):
  8. returnself
  9.  
  10. def next(self):
  11. if self.n < self.max:
  12. r =self.b
  13. self.a, self.b =self.b, self.a +self.b
  14. self.n =self.n +1
  15. return r
  16. raise StopIteration()
  17.  
  18. f=fab(5)
  19. f.next()
  20. f.next()
  21. f.next()
  22. f.next()
  23. f.next()

e)d的代码远远没有a的fab 函数来得简洁。如果我们想要保持第一版 fab 函数的简洁性,同时又要获得 iterable 的效果,yield 就派上用场了

  1. def fab(max):
  2. n, a, b =0, 0, 1
  3. while n < max:
  4. yield b
  5. # print b
  6. a, b =b, a +b
  7. n =n +1
  8.  
  9. for n in fab(5):
  10. print n
  11.  
  12. type(fab(5))
  13.  
  14. 1
  15. 1
  16. 2
  17. 3
  18. 5
  19. generator

f)最后优化的版本在for循环的时候选择xrange并且结果保存在iterator里

  1. def fab(max):
  2. n,a,b=0,0,1
  3. for i in xrange(max):
  4. yield b
  5. a,b,=b,a+b
  6.  
  7. for n in fab(5):
  8. print n

一个带有 yield 的函数就是一个 generator,它和普通函数不同,生成一个 generator 看起来像函数调用,但不会执行任何函数代码,直到对其调用 next()(在 for 循环中会自动调用 next())才开始执行。虽然执行流程仍按函数的流程执行,但每执行到一个 yield 语句就会中断,并返回一个迭代值,下次执行时从 yield 的下一个语句继续执行。看起来就好像一个函数在正常执行的过程中被 yield 中断了数次,每次中断都会通过 yield 返回当前的迭代值。

yield 的好处是显而易见的,把一个函数改写为一个 generator 就获得了迭代能力,比起用类的实例保存状态来计算下一个 next() 的值,不仅代码简洁,而且执行流程异常清晰

  1. from inspect import isgeneratorfunction
  2.  
  3. isgeneratorfunction(fab)
  4.  
  5. True

要注意区分 fab 和 fab(5),fab 是一个 generator function,而 fab(5) 是调用 fab 返回的一个 generator,好比类的定义和类的实例的区别

在一个 generator function 中,如果没有 return,则默认执行至函数完毕,如果在执行过程中 return,则直接抛出 StopIteration 终止迭代

  1. import types
  2.  
  3. isinstance(fab,types.GeneratorType)
  4.  
  5. False
  6.  
  7. isinstance(fab(5),types.GeneratorType)
  8.  
  9. True
  10.  
  11. from collections import Iterable
  12.  
  13. isinstance(fab,Iterable)
  14.  
  15. False
  16.  
  17. isinstance(fab(5),Iterable)
  18.  
  19. True

另一个例子

  另一个 yield 的例子来源于文件读取。如果直接对文件对象调用 read() 方法,会导致不可预测的内存占用。好的方法是利用固定长度的缓冲区来不断读取文件内容。通过 yield,我们不再需要编写读文件的迭代类,就可以轻松实现文件读取

  1. def read_file(fpath):
  2. block_size=1024
  3. with open(fpath,'rb') as f:
  4. while True:
  5. block=f.read(block_size)
  6. if block:
  7. yield block
  8. else:
  9. return
  10.  
  11. rf=read_file("C:/****/cookies.txt")
  12.  
  13. print rf.next()
  14. print rf.next()
  15. print rf.next()

Python Iterable Iterator Yield的更多相关文章

  1. python中的Iterable, Iterator,生成器概念

    https://nychent.github.io/articles/2016-05/about-generator.cn 这个深刻 谈起Generator, 与之相关的的概念有 - {list, s ...

  2. Python(五) 迭代器(Iterable/Iterator/iter())

    原文的链接:http://www.liaoxuefeng.com/wiki/0014316089557264a6b348958f449949df42a6d3a2e542c000/00143178254 ...

  3. 生成器(generator)和迭代(iterable , iterator, iteration)

    在搞清楚Generator之前,我们先讨论一下 iterable , iterator, iteration 1.Iterable 我们知道,在Python中所有东西都是object, 比如说变量,容 ...

  4. python 迭代器 Iterator

    一.可迭代对象定义 可以直接作用于for循环的数据类型有以下几种: 一类是集合数据类型,如list.tuple.dict.set.str.bytes.bytearray等: 一类是generator, ...

  5. 关于Python中的yield

    关于Python中的yield   在介绍yield前有必要先说明下Python中的迭代器(iterator)和生成器(constructor). 一.迭代器(iterator) 在Python中,f ...

  6. (转) Python Generators(生成器)——yield关键字

    http://blog.csdn.net/scelong/article/details/6969276 生成器是这样一个函数,它记住上一次返回时在函数体中的位置.对生成器函数的第二次(或第 n 次) ...

  7. [Python学习]Iterator 和 Generator的学习心得

    [Python学习]Iterator 和 Generator的学习心得 Iterator是迭代器的意思,它的作用是一次产生一个数据项,直到没有为止.这样在 for 循环中就可以对它进行循环处理了.那么 ...

  8. python协程--yield和yield from

    字典为动词“to yield”给出了两个释义:产出和让步.对于 Python 生成器中的 yield 来说,这两个含义都成立.yield item 这行代码会产出一个值,提供给 next(...) 的 ...

  9. 深入理解Python中的yield和send

    send方法和next方法唯一的区别是在执行send方法会首先把上一次挂起的yield语句的返回值通过参数设定,从而实现与生成器方法的交互. 但是需要注意,在一个生成器对象没有执行next方法之前,由 ...

随机推荐

  1. 发布mvc遇到的HTTP错误 403.14-Forbidden解决办法

    发布mvc遇到的HTTP错误 403.14-Forbidden解决办法   <system.webServer>   <validationvalidateIntegratedMod ...

  2. android.app.Activity阅读摘要,有时候会不会需要保持一些现场数据呢? 想让系统帮你退出到后台或者挂掉前做些前置保持工作吗,重点参考吧:

    * * @param savedInstanceState If the activity is being re-initialized after * previously being shut ...

  3. 关于selenium2(webdriver)自动化测试过程中标签页面或者窗口切换的处理解决方案

    1.  通过页面或者window 的name切换: switch_to_frame(name) switch_to_window(name) 那么问题来了,出现2个或者以上窗口时候,新打开的windo ...

  4. varnish 内置函数详细说明

    Subroutine列表 •vcl_recv 在请求开始时候被调用,在请求已经被接收到并且解析后调用.目的就是决定是否处理这个请求,怎么处理,使用哪个后端.vcl_recv以return结束,参数可以 ...

  5. jquery+php+mysql实现Ajax省市县三级联动

    1.第一步建立一个html页面的,放置省.市.县三个select选择框,代码如下: <!DOCTYPE html> <html> <head> <title& ...

  6. Memcache所有方法及参数详解

    memcache函数所有的方法列表如下: 参考http://www.php.net/manual/zh/function.Memcache-add.php Memcache::add - 添加一个值, ...

  7. 【.net部署】Server Error in '/' Application.错误解决方案

    报错: Server Error in '/' Application.---------------------------------------------------------------- ...

  8. EasyUI 开发笔记(一)

    由于某些原因,在公司做的后台需要改成类似于Ext.js 形式的后台,主要看好其中的 框架布局,以及tab开页面和弹出式内部窗体. 后来看看,改成EasyUI,较Ext.js 库小很多,也便于公司的初级 ...

  9. MVC 从后台页面 取前台页面传递过来的值的几种取法

      MVC 从后台页面 取前台页面传递过来的值的几种取法   <1>前台页面 Index视图 注意:用户名表单的name值为txtName 密码表单的name值为txtPassword & ...

  10. SDK截图(四):压缩位图实例

    这个问题研究了两天.<windows程序设计>中没有给出实例,MSDN也没有给出具体的例子.在知道,CSDN提问后,也没有得到答案.所以决定重新对DIB做一次彻底的研究,这大概会花去我一个 ...