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方法之前,由 ...
随机推荐
- 安装mysql sever 向导失败,最后一步无响应
在配置apache+php+mysql环境的时候,apache和php都可以运行,这里提供两个安装教程(window环境) http://apps.hi.baidu.com/share/detail/ ...
- NSIS 让程序以管理权限运行
用NSIS向导,制作安装包,会生成NSI扩展的脚本文件,按F9,即可以生成安装文件. 如果要以管理员权限运行,直接在nsi脚本中,添加RequestExecutionLevel admin Name ...
- html5 请求的URL转成 OC可用属性字符串显示
NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:helpUrlStr]]; NSString *string = [ ...
- SQL注入截取字符串函数
在sql注入中,往往会用到截取字符串的问题,例如不回显的情况下进行的注入,也成为盲注,这种情况下往往需要一个一个字符的去猜解,过程中需要用到截取字符串.本文中主要列举三个函数和该函数注入过程中的一些用 ...
- softwareTesting_work1
1.12306手机APP软件测评 首先是软件界面,iPhone版本和android版本长得是一模一样,虽然是注重功能的软件,但是一样样的界面让人完全感受不到软件设计者的诚意啊. 还有就是软件图片和图标 ...
- 【LeetCode OJ】Same Tree
Problem Link: https://oj.leetcode.com/problems/same-tree/ The following recursive version is accepte ...
- EasyUI 开发笔记(一)
由于某些原因,在公司做的后台需要改成类似于Ext.js 形式的后台,主要看好其中的 框架布局,以及tab开页面和弹出式内部窗体. 后来看看,改成EasyUI,较Ext.js 库小很多,也便于公司的初级 ...
- JAVA EE的十三种技术
java ee 的十三中技术 一.jdbc 1). jdbc-odbc桥 2). jdbc-native 驱动桥 3). jdbc-network 桥 4). 纯java驱动 二. java命令和目录 ...
- redis DB操作
数据库操作 1) REDIS是全部由KEY和VALUE值构成,对数据库的增删改查操作都是基于在通过key 映射到哈希槽 然后通过哈希槽进行单向链式遍历 查找到value和具体的key. 同样 在查看 ...
- day26_网络编程第一天
1.网络通信三要素(掌握) IP 端口号 协议(UPD&TCP) 2.UDP协议与TCP协议各自特点(掌握) UDP 1.不需要建立连接: 2.有数据大小限制,每个 ...