Python 迭代器和生成器

迭代器

Python中的迭代器为类序列对象(sequence-like objects)提供了一个类序列的接口,迭代器不仅可以对序列对象(string、list、tuple)进行迭代,还可以对不是序列,但表现出序列行为的对象进行迭代,例如字典键、文件的行。

迭代器对象有一个next()方法,调用后返回下一个条目。所有条目迭代完后,迭代器引发一个StopIteration异常告诉程序循环结束。for语句可用于序列类型,也可以用于迭代器类型,它会在内部调用next()并捕获异常。

不过,迭代器也有一些限制,它不能向后移动,不能回到开始,也不能复制一个迭代器。

iter(obj)工厂函数可以返回一个迭代器,reversed()函数返回一个反序访问的迭代器,

例如:

t = (123, 'xyz', 45.67)
it = iter(t) # it = reversed(t) 函数返回一个反序访问的迭代器
it.next() #
it.next() # ‘xyz’
it.next() # 45.67
it.next() # StopIteration

iter()方法的另一种使用方式是:iter(func, sentinel),它会重复调用func,直到迭代器的下个值等于sentinel。

a = 1 

def foo():
global a
print(a)
a += 1
return a it = iter(foo, 11)
for i in it:
pass

上面的例子中,for循环会在i=11的时候停下来。

我们知道,for语句接受可迭代对象(序列或迭代器)作为其参数,每次迭代其中一个元素。它会自动调用迭代器的next()方法,捕获StopIteration异常并结束循环,而这一切都是在内部发生的。例如:

for c in "hello world" : print c

上面是通过序列项迭代元素,下面介绍一种使用range函数进行序列索引迭代的方法。

range函数返回一个list,它有三种调用形式:

range(start, end, step)
range(start, end) # step = 1
range(end)     # start=0, step=1

例如:

for eachVal in range(2, 19, 3):
print "value is: ", eachVal

注意,当有有一个很大范围的列表时,xrange()可能更为适合,因为它不会在内存里创建列表的完整拷贝,它只能被用在for循环中,在for循环外使用没有意义。

另外,xrange()返回的是一个xrange对象,这既不是一个序列对象,也不是一个迭代器对象。

xrange()的用法跟range()完全一样:

for eachVal in xrange(2, 19, 3):
print "value is: ", eachVal

但xrange不会返回一个list,而是每次循环返回一个值,性能更好些,后面会介绍生成器表达式,也是类似的原理。

另外,在迭代可改变对象的时候不要修改它们。

lst = range(10)
print(lst) for ele in lst:
ele = ele*3 print(lst)

可以发现,lst没有任何改变。

如果要修改迭代的对象,可以使用索引迭代:

lst = range(10)
print(lst) for k in range(len(lst)):
lst[k] = lst[k]*3 print(lst)

列表解析

列表解析的语法:

[expr for iter_var in iterable if cond_expr]

返回一个列表。

例如:

seq = [1, 2, 3, 4 ,5, 6, 7, 8, 9]
[item for item in seq if item%2]
# [1, 3, 5, 7, 9]

又比如打印一个3*5的矩阵:

[(x+1, y+1) for x in range(3) for y in range(5)]

生成器表达式

生成器表达式与列表解析的用法一样,只是把"[]"换成了 “()”,但生成器表达式返回不是list,而是生成器(generator),生成器本质上是一种函数。

生成器在每次计算出一个条目后,把这个条目yield出来,它使用了一种延迟计算(lazy evaluation),所以在内存上更有效。

例如:

>>> matrix = ((x+1, y+1) for x in range(3) for y in range(5))
>>> for i in matrix: print(i)
...
(1, 1)
(1, 2)
(1, 3)
(1, 4)
(1, 5)
(2, 1)
(2, 2)
(2, 3)
(2, 4)
(2, 5)
(3, 1)
(3, 2)
(3, 3)
(3, 4)
(3, 5)

再比如,如果想得到一个很大的文本文件最长的行:

max( len(line.strip()) for line in open('/etc/motd') )

如果这里使用列表解析,那么不可避免需要把整个文件的所有行都加载到内存中,而是要生成器表达式在性能上会更好。

生成器

生成器的本质是一个带yield语句的函数,通常一个函数只能返回一次,而生成器能暂停执行并返回一个中间的结果(yield语句的功能),返回一个值给调用者并暂停执行。当生成器的next()方法被调用的时候,它会准确地从离开地方继续。

可见,生成器跟协程的概念很类似,可以暂停或者挂起,并从程序离开的地方继续执行。

rows = [1, 2, 3, 17]

def cols():
yield 56
yield 2
yield 1 x_product_pairs = ((i,j) for i in rows for j in cols()) for pair in x_product_pairs:
print(pair)

运行结果:

(, )
(, )
(, )
(, )
(, )
(, )
(, )
(, )
(, )
(, )
(, )
(, )

当调用生成器的next()方法时,生成器会执行,直至出现yield语句,并把yield的参数返回给调用者(类似于return)。

注意,yield语句后面的代码不会再运行。需要下次继续调用next()方法才会继续执行,直至函数退出。

此外,调用者也可用将值回送给生成器(通过send()方法),以及要求生成器退出(close())。

例子:

def counter(start_at=0):
count = start_at
while True:
val = (yield count)
if val is not None:
print("val is not None ", val)
count = val
else:
count += 1 c = counter(5)
print(c.next()) #
print(c.next()) #
print(c.next()) # c.send(100)
print(c.next()) # c.close()
c.next() #StopIteration

生成器带有一个初始化的值,每次调用生成器next()时对count累加1,用户可以send()重置这个值;而调用close()方法,会终结生成器。

Python之迭代器和生成器的更多相关文章

  1. python基础—迭代器、生成器

    python基础-迭代器.生成器 1 迭代器定义 迭代的意思是重复做一些事很多次,就像在循环中做的那样. 只要该对象可以实现__iter__方法,就可以进行迭代. 迭代对象调用__iter__方法会返 ...

  2. python之迭代器与生成器

    python之迭代器与生成器 可迭代 假如现在有一个列表,有一个int类型的12345.我们循环输出. list=[1,2,3,4,5] for i in list: print(i) for i i ...

  3. 【Python】迭代器、生成器、yield单线程异步并发实现详解

    转自http://blog.itpub.net/29018063/viewspace-2079767 大家在学习python开发时可能经常对迭代器.生成器.yield关键字用法有所疑惑,在这篇文章将从 ...

  4. python的迭代器、生成器、装饰器

    迭代器.生成器.装饰器 在这个实验里我们学习迭代器.生成器.装饰器有关知识. 知识点 迭代器 生成器 生成器表达式 闭包 装饰器 实验步骤 1. 迭代器 Python 迭代器(Iterators)对象 ...

  5. Python之迭代器,生成器

    迭代器 1.什么是可迭代对象 字符串.列表.元组.字典.集合都可以被for循环,说明他们都是可迭代的. from collections import Iterable l = [1,2,3,4] t ...

  6. python之迭代器、生成器与面向过程编程

    目录 一 迭代器 二 生成器 三 面向过程编程 一.迭代器 1.迭代器的概念理解 ''' 迭代器从字面上理解就是迭代的工具.而迭代是每次的开始都是基于上一次的结果,不是周而复始的,而是不断发展的. ' ...

  7. day13 python学习 迭代器,生成器

    1.可迭代:当我们打印 print(dir([1,2]))   在出现的结果中可以看到包含 '__iter__', 这个方法,#次协议叫做可迭代协议 包含'__iter__'方法的函数就是可迭代函数 ...

  8. Python之迭代器及生成器

    一. 迭代器 1.1 什么是可迭代对象 字符串.列表.元组.字典.集合 都可以被for循环,说明他们都是可迭代的. 我们怎么来证明这一点呢? from collections import Itera ...

  9. python基础----迭代器、生成器、协程函数及应用(面向过程实例)

    一.什么是迭代器协议 1.迭代器协议是指:对象必须提供一个next方法,执行该方法要么返回迭代中的下一项,要么就引起一个StopIteration异常,以终止迭代 (只能往后走不能往前退) 2.可迭代 ...

随机推荐

  1. 【CodeForces 699D】Fix a Tree

    dfs找出联通块个数cnt,当形成环时,令指向已访问过节点的节点变成指向-1,即做一个标记.把它作为该联通图的根. 把所有联通的图变成一颗树,如果存在指向自己的点,那么它所在的联通块就是一个树(n-1 ...

  2. CocoaPods安装与使用

    CocoaPods简介: CocoaPods 是什么? CocoaPods 是开发 OS X 和 iOS 应用程序的一个第三方库的依赖管理工具.利用 CocoaPods,可以定义自己的依赖关系 (称作 ...

  3. 编译hadoop-2.5.2总结

    原文:http://www.cnblogs.com/qigang/p/4194728.html 一.准备的资料 64位linux系统.我使用的是 CentOS JDK 1.7+.注:使用1.7即可,如 ...

  4. php发送http put/patch/delete请求

    今天学RESTful API的编写,发现不知道怎么发送HTTP PUT/PATCH/DELETE请求,还是要学习一个. 使用curl_opt函数来发送各式各样的http请求动作,不仅限于get和pos ...

  5. Slave2: no datanode to stop(权限)

    有些datanode没有启动,要么是id不一致,我删除了还是不行,要么是权限问题,我邮件属性查看权限,发现不是hxsyl组,我删除,重建.

  6. [PHP 作为iOS后台Json格式HTTP通信及文件上传的实现]

    1.数据库连接 configmysql.php <?php $q = mysql_connect("localhost:8889","root",&quo ...

  7. MVC5-10 从模型验证来说内部那些事

    源码解析 模型验证几乎在大部分的项目中都在被使用,这方面的博文教程也很多,关于那些更详细的模型验证这里就不多赘述了,主要讲解内部是如何进行验证的. 在前几篇博文中提到了DefaultModelBind ...

  8. Linux使用网盘客户端

    1. 百度网盘 - bypy https://github.com/houtianze/bypy 这是一个基于Python的命令行客户端. 安装参考上面链接的说明,或者这篇文章(推荐,有告诉你如何安装 ...

  9. iOS - CAEmitterLayer 学习笔记一

    其他参考博客: http://my.oschina.net/u/2340880/blog/485095 http://www.cnblogs.com/YouXianMing/p/3785876.htm ...

  10. hibernate......1、2级缓存

    1.什么是缓存? 缓存是介于物理数据源与应用程序之间,是对数据库中的数据复制一份临时放在内存中的容器,其作用是为了减少应用程序对物理数据源访问的次数,从而提高了应用程序的运行性能.Hibernate在 ...